Roma:
Shellless detectado, 32 bits
Abra-o diretamente com IDA e vá para a função principal
int func()
{
int result; // eax
int v1[4]; // [esp+14h] [ebp-44h]
unsigned __int8 v2; // [esp+24h] [ebp-34h] BYREF
unsigned __int8 v3; // [esp+25h] [ebp-33h]
unsigned __int8 v4; // [esp+26h] [ebp-32h]
unsigned __int8 v5; // [esp+27h] [ebp-31h]
unsigned __int8 v6; // [esp+28h] [ebp-30h]
int v7; // [esp+29h] [ebp-2Fh]
int v8; // [esp+2Dh] [ebp-2Bh]
int v9; // [esp+31h] [ebp-27h]
int v10; // [esp+35h] [ebp-23h]
unsigned __int8 v11; // [esp+39h] [ebp-1Fh]
char v12[29]; // [esp+3Bh] [ebp-1Dh] BYREF
strcpy(v12, "Qsw3sj_lz4_Ujw@l");
printf("Please input:");
scanf("%s", &v2);
result = v2;
if ( v2 == 65 )
{
result = v3;
if ( v3 == 67 )
{
result = v4;
if ( v4 == 84 )
{
result = v5;
if ( v5 == 70 )
{
result = v6;
if ( v6 == 123 )
{
result = v11;
if ( v11 == 125 )
{
v1[0] = v7;
v1[1] = v8;
v1[2] = v9;
v1[3] = v10;
*(_DWORD *)&v12[17] = 0;
while ( *(int *)&v12[17] <= 15 )
{
if ( *((char *)v1 + *(_DWORD *)&v12[17]) > 64 && *((char *)v1 + *(_DWORD *)&v12[17]) <= 90 )
*((_BYTE *)v1 + *(_DWORD *)&v12[17]) = (*((char *)v1 + *(_DWORD *)&v12[17]) - 51) % 26 + 65;// A到O
if ( *((char *)v1 + *(_DWORD *)&v12[17]) > 96 && *((char *)v1 + *(_DWORD *)&v12[17]) <= 122 )
*((_BYTE *)v1 + *(_DWORD *)&v12[17]) = (*((char *)v1 + *(_DWORD *)&v12[17]) - 79) % 26 + 97;
++*(_DWORD *)&v12[17];
}
*(_DWORD *)&v12[17] = 0;
while ( *(int *)&v12[17] <= 15 )
{
result = (unsigned __int8)v12[*(_DWORD *)&v12[17]];
if ( *((_BYTE *)v1 + *(_DWORD *)&v12[17]) != (_BYTE)result )
return result;
++*(_DWORD *)&v12[17];
}
return printf("You are correct!");
}
}
}
}
}
}
return result;
}
Ao ver a string v12 na frente, você sabe que provavelmente é a string chave usada para verificação no final e, em seguida, insira a string v2.
Vendo que a "string" v2 é dada à variável temporária como um resultado de quatro bytes no início, isso não é razoável.
Veja a definição de variáveis acima. Na verdade, isso armazena a string na pilha começando com v2 como o primeiro endereço.
E armazene do endereço alto para o endereço baixo (observe que isso é uma pilha)
Ele foi armazenado até a v11. Conte, são 22 bytes no total, porque a imagem acima mostra que a v11 armazena "}"
Além disso, os ifs consecutivos acima representam apenas coisas fora dos colchetes e são inúteis. Eles são usados apenas como identificadores.
Vejamos diretamente a parte central
Aqui está o ponto principal, *(_DWORD *)&v12[17] significa pegar o primeiro endereço de v12 (o tipo char definido na parte superior, ocupando um byte) e, em seguida, convertê-lo à força em um ponteiro do tipo dd e, em seguida, atribuí-lo em a forma de um ponteiro Quatro bytes são um número inteiro 0 (ou seja,
int v12=0)
Todas as coisas aqui *(_DWORD *)&v12[17] podem ser consideradas como uma variável temporária, como índice
Não fique cego aqui também.
Na verdade, o tipo int v1 e seu endereço inicial são convertidos em tipo byte. Neste momento, ainda é um ponteiro, e então o ponteiro é adicionado ao índice que mencionei acima e, finalmente, * então se torna um valor real, que é na verdade uma matriz de strings.
Depois de saber disso, o funcionamento do programa a seguir é extremamente simples, ou seja, é feito um simples deslocamento para letras maiúsculas e minúsculas, retrocedendo 14 bits e retrocedendo 18 bits respectivamente.
Existem duas maneiras de escrever o script para esta pergunta:
A primeira é inverter o turno e escrever o script
É recomendado usar python aqui, porque python é uma operação de módulo (C/java é uma operação de resto), e a operação de módulo é mais conveniente para mudar números negativos (você sabe)
A seguir está um script fixo para criptografia e descriptografia do tipo César
key="Qsw3sj_lz4_Ujw@l"
flag=""
for c in key:
if c>='a' and c<='z':
flag+=chr((ord(c)-18-97)%26+97)
elif c>='A' and c<='Z':
flag+=chr((ord(c)-14-65)%26+65)
else:
flag+=c
print(flag)
##原始数据加减移位值,-97或者是-65然后%26变为索引值,再加上97或者是65变为asiic码
O segundo tipo é a explosão direta (ou seja, a explosão da bandeira original ou valor não intermediário)
key="Qsw3sj_lz4_Ujw@l"
flag=""
for i in range(16):
if key[i]<='Z' and key[i]>='A':
for j in range(65,91,1):
if ord(key[i]) == (j-51)%26+65:
flag+=chr(j)
break
elif key[i]<='z' and key[i]>='a':
for j in range(97, 123, 1):
if ord(key[i]) == (j - 79) % 26 + 97:
flag += chr(j)
break
else:
flag+=key[i]
print(flag)
obter bandeira{Cae3ar_th4_Gre@t}
fácil
Se houver um shell, remova-o primeiro, shell UPX
Venha para a função principal
Uma breve olhada nisso é forçar a conversão da parte central do sinalizador para o tipo de byte, depois diminuir o valor do código asiic e defini-lo como o valor do índice e, em seguida, compará-lo com a v4, um por um.
escrever um roteiro
key="*F'\"N,\"(I?+@"
flag=""
list=[]
data="~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$# !\""
for i in range(12):
for j in range(len(data)):
if key[i]==data[j]:
list.append(j)
break;
for i in range(12):
flag += chr(list[i] + 1)
print(flag)
sinalizar{U9X_1S_W6@T?}
pira (python reverso)
é um arquivo pyc
Obtenha-o em um site online e descompile-o
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 2.7
print 'Welcome to Re World!'
print 'Your input1 is your flag~'
l = len(input1)
for i in range(l):
num = ((input1[i] + i) % 128 + 128) % 128
code += num
for i in range(l - 1):
code[i] = code[i] ^ code[i + 1]
print code
code = [
'%1f',
'%12',
'%1d',
'(',
'0',
'4',
'%01',
'%06',
'%14',
'4',
',',
'%1b',
'U',
'?',
'o',
'6',
'*',
':',
'%01',
'D',
';',
'%',
'%13']
Escreva o script (avançar e retroceder para facilitar a comparação)
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 2.7
input1="flag{Just_Re_1s_Ha66y!}"
code=[]
l = len(input1)
for i in range(l):
num = ((ord(input1[i]) + i) % 128 + 128) % 128
code.append(num)
print(code)
for i in range(l - 1):
code[i] = code[i] ^ code[i + 1]
code = [
'\x1f',
'\x12',
'\x1d',
'(',
'0',
'4',
'\x01',
'\x06',
'\x14',
'4',
',',
'\x1b',
'U',
'?',
'o',
'6',
'*',
':',
'\x01',
'D',
';',
'%',
'\x13']
for i in range(len(code)-2,-1,-1):
code[i]=chr(ord(code[i])^ord(code[i+1]))
print(code)
flag=""
for i in range(len(code)):
flag+=chr((ord(code[i])-i)%128)
print(flag)
sinalizador{Just_Re_1s_Ha66y!}
Raspe e ganhe prêmios
Abra o IDA sem shell. Se a função principal não puder ser encontrada, procure por strings para visualizar strings sensíveis e veja a imagem abaixo.
sub_4010F0 pode ser revisado posteriormente
As duas funções a seguir possuem strings confidenciais relacionadas a base64
As duas strings a seguir são decodificadas e, em seguida, reproduzidas para obter v7, v10
Código de revisão:
#include <iostream>
using namespace std;
void sub_4010F0(char *a1, int a2, int a3)
{
int result; // eax
int i; // esi
int v5; // ecx
int v6; // edx
result = a3;
for ( i = a2; i <= a3; a2 = i )
{
v5 = i;
v6 = a1[i];
if ( a2 < result && i < result )
{
do
{
if ( v6 > a1[result] )
{
if ( i >= result )
break;
++i;
a1[v5] = a1[result];
if ( i >= result )
break;
while ( a1[i] <= v6 )
{
if ( ++i >= result )
goto LABEL_13;
}
if ( i >= result )
break;
v5 = i;
a1[result] = a1[i];
}
--result;
}
while ( i < result );
}
LABEL_13:
a1[result] = v6;
sub_4010F0(a1, a2, i - 1);
result = a3;
++i;
}
}
int main(){
char str[]="ZJSECaNH3ng";
sub_4010F0(str,0,10);
printf("%s\n",str);
return 0;
}
P: Por que 4*i no IDA original muda para i?
R: Posso ser considerado um índice. Essas coisas estranhas são todas transformações de arrays.
obter bandeira
sinalizador{UJWP1jMp}