新手刚开始学习逆向,有很多地方说得不对或者不好还希望各位表哥能指正
Windows Reverse1
0x01
首先exeinfo查一下壳,发现是upx壳
0x02
脱壳
这里针对upx壳有很多办法,我就挑一个好懂的和一个好用的说
1、首先是ESP定律脱壳,这里先载入OD,F8单步一次
注意观察右边寄存器esp的变化,选中esp,选择在数据窗口中跟随
可以看到这时左下方窗口中跟踪到数值所对应的地址正对应esp,在这里下硬件断点,选择断点-->硬件访问-->word
F9运行一下
[Asm] 纯文本查看 复制代码 00407C47 . 8D4424 80 lea eax,dword ptr ss:[esp-0x80]
00407C4B > 6A 00 push 0x0
00407C4D . 39C4 cmp esp,eax
00407C4F .^ 75 FA jnz short reverse1.00407C4B
00407C51 . 83EC 80 sub esp,-0x80
00407C54 .- E9 9E97FFFF jmp reverse1.004013F7
F4运行到7c51,F8步过一次,达到oep
[Asm] 纯文本查看 复制代码 004013F7 E8 7C040000 call reverse1.00401878
004013FC ^ E9 9FFDFFFF jmp reverse1.004011A0
00401401 8BFF mov edi,edi
00401403 55 push ebp
00401404 8BEC mov ebp,esp
00401406 81EC 28030000 sub esp,0x328
0040140C A3 A0314000 mov dword ptr ds:[0x4031A0],eax
00401411 890D 9C314000 mov dword ptr ds:[0x40319C],ecx
2、然后是一步到位法
od载入后ctrl+f搜索出栈指令
可以看到又到了上边的地址
[Asm] 纯文本查看 复制代码 00407C46 . 61 popad
00407C47 . 8D4424 80 lea eax,dword ptr ss:[esp-0x80]
00407C4B > 6A 00 push 0x0
00407C4D . 39C4 cmp esp,eax
00407C4F .^ 75 FA jnz short reverse1.00407C4B
00407C51 . 83EC 80 sub esp,-0x80
00407C54 .- E9 9E97FFFF jmp reverse1.004013F7
lordpe提取一下
这时候修复一下iat
0x03
找到地址后import rce获取输入表转储到文件即可,IDA分析一波,直接F5大法
[C] 纯文本查看 复制代码 int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax@2
char v4; // [sp+4h] [bp-804h]@1
char v5; // [sp+5h] [bp-803h]@1
char v6; // [sp+404h] [bp-404h]@1
char Dst; // [sp+405h] [bp-403h]@1
v6 = 0;
memset(&Dst, 0, 0x3FFu);
v4 = 0;
memset(&v5, 0, 0x3FFu);
printf("please input code:");
scanf("%s", &v6);
sub_401000(&v6);
if ( !strcmp(&v4, "DDCTF{reverseME}") )
{
printf("You've got it!!%s\n", &v4);
result = 0;
}
else
{
printf("Try again later.\n");
result = 0;
}
return result;
}
分析一下对输入内容的check
[C] 纯文本查看 复制代码 unsigned int __cdecl sub_401000(const char *a1)
{
_BYTE *v1; // ecx@0
unsigned int v2; // edi@1
unsigned int result; // eax@1
int v4; // ebx@2
v2 = 0;
result = strlen(a1);
if ( result )
{
v4 = a1 - v1;
do
{
*v1 = byte_402FF8[v1[v4]];
++v2;
++v1;
result = strlen(a1);
}
while ( v2 < result );
}
return result;
}
可以发现这货啥都没干,那我们也不必看下去,可以直接OD载入,nop掉判断,输入DDCTF{reverseME}
[Asm] 纯文本查看 复制代码 004010FB 90 nop
004010FC 90 nop
004010FD 8D4C24 04 lea ecx,dword ptr ss:[esp+0x4]
00401101 51 push ecx
00401102 68 20214000 push dumped_.00402120 ; You've got it!!%s\n
00401107 FFD6 call esi
00401109 83C4 08 add esp,0x8
0040110C 33C0 xor eax,eax
0040110E 5E pop esi ; kernel32.7C817077
0040110F 8B8C24 00080000 mov ecx,dword ptr ss:[esp+0x800]
00401116 33CC xor ecx,esp
00401118 E8 29000000 call dumped_.00401146
0040111D 81C4 04080000 add esp,0x804
00401123 C3 retn
check通过
Windows Reverse2
0x01
继续exeinfo查壳,发现是aspack,接着手脱即可
脱壳步骤和上边的re1基本一致,使用esp定律脱掉即可,这里不多赘述
0x02
载入ida分析,F5大法
[C] 纯文本查看 复制代码 int __cdecl main(int argc, const char **argv, const char **envp)
{
char Dest; // [sp+8h] [bp-C04h]@4
char v5; // [sp+9h] [bp-C03h]@4
char v6; // [sp+408h] [bp-804h]@1
char Dst; // [sp+409h] [bp-803h]@1
char v8; // [sp+808h] [bp-404h]@1
char v9; // [sp+809h] [bp-403h]@1
v6 = 0;
memset(&Dst, 0, 0x3FFu);
v8 = 0;
memset(&v9, 0, 0x3FFu);
printf("input code:");
scanf("%s", &v6);
if ( !(unsigned __int8)sub_4011F0() )
{
printf("invalid input\n");
exit(0);
}
sub_401240(&v8);
Dest = 0;
memset(&v5, 0, 0x3FFu);
sprintf(&Dest, "DDCTF{%s}", &v8);
if ( !strcmp(&Dest, "DDCTF{reverse+}") )
printf("You've got it !!! %s\n", &Dest);
else
printf("Something wrong. Try again...\n");
return 0;
}
首先看一下sub_4011F0函数
[C] 纯文本查看 复制代码 char __usercall sub_4011F0@<al>(const char *a1@<esi>)
{
signed int v1; // eax@1
signed int v2; // edx@1
int v3; // ecx@3
char v4; // al@4
v1 = strlen(a1);
v2 = v1;
if ( v1 && v1 % 2 != 1 )
{
v3 = 0;
if ( v1 <= 0 )
return 1;
while ( 1 )
{
v4 = a1[v3];
if ( (v4 < 48 || v4 > 57) && (v4 < 65 || v4 > 70) )
break;
if ( ++v3 >= v2 )
return 1;
}
}
return 0;
}
可以看出输入16进制字符串可以通过验证,然后是sub_401240函数
[C] 纯文本查看 复制代码 int __usercall sub_401240@<eax>(const char *a1@<esi>, int a2)
{
signed int v2; // edi@1
unsigned int v3; // edx@1
char v4; // bl@2
char v5; // al@3
char v6; // al@7
unsigned int v7; // ecx@11
char v9; // [sp+Bh] [bp-405h]@0
char v10; // [sp+Ch] [bp-404h]@1
char Dst; // [sp+Dh] [bp-403h]@1
v2 = strlen(a1);
v10 = 0;
memset(&Dst, 0, 0x3FFu);
v3 = 0;
if ( v2 > 0 )
{
v4 = v9;
do
{
v5 = a1[v3];
if ( (unsigned __int8)(a1[v3] - 48) > 9u )
{
if ( (unsigned __int8)(v5 - 65) <= 5u )
v9 = v5 - 55;
}
else
{
v9 = a1[v3] - 48;
}
v6 = a1[v3 + 1];
if ( (unsigned __int8)(a1[v3 + 1] - 48) > 9u )
{
if ( (unsigned __int8)(v6 - 65) <= 5u )
v4 = v6 - 55;
}
else
{
v4 = a1[v3 + 1] - 48;
}
v7 = v3 >> 1;
v3 += 2;
*(&v10 + v7) = v4 | 16 * v9;
}
while ( (signed int)v3 < v2 );
}
return sub_401000(v2 / 2, (void *)a2);
}
好吧其实是有点长的,但是这里可以使些小技俩,结合程序本身进行推测,首先是第一段验证,只允许输入16进制字符串,那就随便输入个AF进去
可以看到输出结果很像base64编码,试着解码一下
那么就很简单了,我们开始构造payload
0x03
对最终需要进行对比的内容逆向分析,显然要经过base64解码,然后再转为16进制
用python构造一下
[Python] 纯文本查看 复制代码 >>> import base64
>>> import binascii
>>> a = 'reverse+'
>>> print(binascii.b2a_hex(base64.b64decode(a)).upper())
b'ADEBDEAEC7BE'
验证通过
|