学习记录!
peid查看下发现加壳了的。不是很难的一个壳。双击运行下如下图:
OD载入查找字符串,发现并没有效果。先脱壳再说吧。
00401220 > $ B8 DC0F4500 mov eax,crackme4.00450FDC
00401225 ? 50 push eax
00401226 . 64:FF35 00000>push dword ptr fs:[0]
0040122D . 64:8925 00000>mov dword ptr fs:[0],esp ;在这里对esp下硬件断点,再运行
00401234 ? 33C0 xor eax,eax
00401236 ? 8908 mov dword ptr ds:[eax],ecx
接下来来到:
0045100B 83C4 04 add esp,0x4
0045100E 55 push ebp
0045100F 53 push ebx
00451010 51 push ecx
00451011 57 push edi
00451012 56 push esi
00451013 52 push edx
00451014 8D98 57121600 lea ebx,dword ptr ds:[eax+0x161257]
0045101A 8B53 18 mov edx,dword ptr ds:[ebx+0x18]
0045101D 52 push edx
0045101E 8BE8 mov ebp,eax
00451020 6A 40 push 0x40
00451022 68 00100000 push 0x1000
00451027 FF73 04 push dword ptr ds:[ebx+0x4]
0045102A 6A 00 push 0x0
0045102C 8B4B 10 mov ecx,dword ptr ds:[ebx+0x10]
0045102F 03CA add ecx,edx
00451031 8B01 mov eax,dword ptr ds:[ecx]
00451033 FFD0 call eax ;调用VirtualAlloc 继续运行
00451035 5A pop edx
然后会在这里断下:
0045109D 5D pop ebp ; 0028FF94
0045109E FFE0 jmp eax
运行完后就会跳转到oep处,dump下来即可,这个壳网上的例子很多。
用IDA分析会直接来到main处,查看整个函数,很容易发现gets函数,控制台的程序用gets获取字符串也很正常。
.text:0040144C movzx eax, byte_440035
.text:00401453 mov [ebp+var_60], al
.text:00401456 lea eax, [ebp+var_28]
.text:00401459 mov [esp], eax ; char *
.text:0040145C
call sub_401756
.text:00401461 lea eax, [ebp+var_38]
.text:00401464 mov [esp], eax ; char *
.text:00401467
call sub_401756
.text:0040146C lea eax, [ebp+var_88]
.text:00401472 mov [esp], eax
.text:00401475 call sub_40152E
.text:0040147A lea eax, [ebp+var_48]
.text:0040147D mov [esp], eax ; char *
.text:00401480
call sub_401756
.text:00401485 lea eax, [ebp+var_B8]
.text:0040148B mov [esp], eax ; char *
.text:0040148E call gets
.text:00401493 lea eax, [ebp+var_C8]
同样用OD载入在40148E处断,如下图 在输入password时才断,说明前面还有一个gets 先不管,注意已经写到内存28FE90处了。
下面一个函数4016F2用IDA跟进参数为地址28FE80处
int __cdecl sub_4016F2(int a1)
{
int result; // eax@1
*(_BYTE *)a1 = 118;
*(_BYTE *)(a1 + 7) = 91;
*(_BYTE *)(a1 + 1) = 3;
*(_BYTE *)(a1 + 5) = 85;
*(_BYTE *)(a1 + 2) = 64;
*(_BYTE *)(a1 + 9) = 100;
*(_BYTE *)(a1 + 3) = 112;
*(_BYTE *)(a1 + 4) = 2;
*(_BYTE *)(a1 + 6) = 91;
*(_BYTE *)(a1 + 8) = 5;
result = a1 + 10;
*(_BYTE *)(a1 + 10) = 0;
return result;
}
就是将这些值写进去10个字节
0028FE80 76 03 40 70 02 55 5B 5B 05 64 00 00 F8 FE 28 00 v@pU[[d..(.
0028FE90 31 32 33 34 35 00 80 02 FE FF FF FF AA 38 DE 77 12345.€??辸
0028FEA0 A2 34 DE 77 00 00 00 00 98 2F 7E 00 98 2F 7E 00 ?辸....?~.?~.
0028FEB0 00 00 00 00 00 00 00 00 90 2F 7E 00 08 FF 28 00 ........?~.(.
0028FEC0 37 33 38 38 37 38 36 35 00 00 00 00 DA 98 F9 76 73887865....跇鵹
上一行为写进去的值每次不变,下一行是自己输入的password。这里应该输入10个字符的。接着向下运行
004014AB |> /83BD 34FFFFFF>/cmp [local.51],0x9 ; 循环10次
004014B2 |. |7F 58 |jg Xduan.
0040150C
004014B4 |. |8D45 F8 |lea eax,[local.2]
004014B7 |. |0385 34FFFFFF |add eax,[local.51]
004014BD |. |2D C0000000 |sub eax,0xC0 ; 0028FE80 自动生成的那个字符串
004014C2 |. |0FBE10 |movsx edx,byte ptr ds:[eax] ; 取一个字符给edx
004014C5 |. |8D45 F8 |lea eax,[local.2]
004014C8 |. |0385 34FFFFFF |add eax,[local.51]
004014CE |. |2D B0000000 |sub eax,0xB0 ; 0028FE90 输入的password
004014D3 |. |0FBE00 |movsx eax,byte ptr ds:[eax] ; 取一个字符给eax
004014D6 |. |31C2 |xor edx,eax ; 将取的两个字符异或
004014D8 |. |8D45 F8 |lea eax,[local.2]
004014DB |. |0385 34FFFFFF |add eax,[local.51]
004014E1 |. |83C0 80 |add eax,-0x80 ; 0028FEC0 另外的字符串
004014E4 |. |0FBE00 |movsx eax,byte ptr ds:[eax] ; 取一个给eax
004014E7 |. |39C2 |cmp edx,eax
004014E9 |. |74 17 |je Xduan.
00401502 ; 相等循环下一次 否则失败
004014EB |. |8D45 A8 |lea eax,[local.22]
004014EE |. |890424 |mov dword ptr ss:[esp],eax
004014F1 |. |E8 60020000
|call duan.00401756 ;失败
004014F6 |. |C785 30FFFFFF>|mov [local.52],0x0
00401500 |. |EB 24 |jmp Xduan.00401526
00401502 |> |8D85 34FFFFFF |lea eax,[local.51]
00401508 |. |FF00 |inc dword ptr ds:[eax] ;加1
0040150A |.^\EB 9F \jmp Xduan.
004014AB
0040150C |> 8D45 98 lea eax,[local.26]
0040150F |. 890424 mov dword ptr ss:[esp],eax
00401512 |. E8 3F020000 call duan.00401756
00401517 |. E8 44D20000 call <jmp.&msvcrt._getch> ; [_getch
0040151C |. C785 30FFFFFF>mov [local.52],0x0
00401526 |> 8B85 30FFFFFF mov eax,[local.52]
0040152C |. C9 leave
0040152D \. C3 retn
说明10次异或成功应该能成功,重新运行输入xdsec,1234567890.发现28FEC0处的变了,说明这个字符串与输入的name有关,不过这里并不需要了解是怎么转变的,新的字符串为
0028FEC0 38 33 37 33 37 34 38 30 36 36 00 00 DA 98 F9 8373748066..跇鵹
将这个字符串与28FE80处的异或即可得到password为4E3077433561636B3352(十六进制)字符串为N0wC5ack3R。
接下来看看name字符串是怎么变形的,在gets函数上有两个函数调用,分别断即可找到。
signed int __cdecl sub_40152E(int a1)
{
signed int result; // eax@11
signed int i; // [sp+28h] [bp-30h]@1
signed int j; // [sp+28h] [bp-30h]@10
size_t v4; // [sp+2Ch] [bp-2Ch]@1
char v5; // [sp+30h] [bp-28h]@1
char v6[8]; // [sp+50h] [bp-8h]@3
gets(&v5);
v4 = strlen(&v5);
for ( i = 0; i < (signed int)v4; ++i )
{
if ( v6[i - 32] <= 96 || v6[i - 32] > 122 )
{
if ( v6[i - 32] > 64 )
{
if ( v6[i - 32] <= 90 )
v6[i - 32] = (7 * (v6[i - 32] - 65) + 13) % 26 + 65;
}
}
else
{
v6[i - 32] = (7 * (v6[i - 32] - 97) + 13) % 26 + 65;
}
}
for ( j = 0; ; ++j )
{
result = j;
if ( j >= (signed int)v4 )
break;
*(_BYTE *)(a1 + 2 * j) = v6[j - 32] / 10 + 48;
*(_BYTE *)(a1 + 2 * j + 1) = v6[j - 32] % 10 + 48;
*(_BYTE *)(a1 + 2 * j + 2) = 0;
}
return result;
}
分析得y=7*(x+13)mod26+65,是一个放射密码。