学破解第107天,《攻防世界reverse练习区srm-50》分析
前言:
一直对黑客充满了好奇,觉得黑客神秘,强大,无所不能,来论坛两年多了,天天看各位大佬发帖,自己只能做一个伸手党。也看了官方的入门视频教程,奈何自己基础太差,看不懂。自我反思之下,决定从今天(2019年6月17日)开始定下心来,从简单的基础教程开始学习,希望能从照抄照搬,到能独立分析,能独立破解。
不知不觉学习了好几个月,发现自己离了教程什么都不会,不懂算法,不懂编程。随着破解学习的深入,楼主这个半吊子迷失了自我,日渐沉迷水贴装X,不能自拔。
==========申明:从第71天楼主开始水贴装X,帖子不再具有连续性,仅供参考,后续帖子为楼主YY专用贴!!!==========
立帖为证!--------记录学习的点点滴滴
0x1下载程序
1.首先查壳,显示Microsoft Visual C++ v.14 - 2015 ( E8 ),无壳。
2.运行程序看看,程序让我们输入邮箱和序列号,(注意这里如果随便输入会提示格式不正确)弹出注册失败的提示信息。
0x2上OD
1.丢进吾爱的OD跑起来,搜索字符串,看到错误
004013B0 |. 0F2805 A00A41>movaps xmm0,dqword ptr ds:[0x410AA0] ; Registration fai
004013B7 |. 8D8D C0FDFFFF lea ecx,[local.144]
004013BD |. 0F1145 E4 movups dqword ptr ss:[ebp-0x1C],xmm0
004013C1 |. 8D51 01 lea edx,dword ptr ds:[ecx+0x1]
004013C4 |. C745 F4 6C757>mov [local.3],0x6572756C
004013CB |. 0F2805 900A41>movaps xmm0,dqword ptr ds:[0x410A90] ; Registration SucRegistration fai
004013D2 |. 0F1145 C0 movups dqword ptr ss:[ebp-0x40],xmm0
004013D6 |. 66:C745 F8 2E>mov word ptr ss:[ebp-0x8],0x2E
004013DC |. 0F2805 800A41>movaps xmm0,dqword ptr ds:[0x410A80] ; cess!\nYour flag Registration SucRegistration fai
2.很好,定位到关键函数了,向上翻,看到了
0040130C |. 68 00010000 push 0x100 ; /Count = 100 (256.)
00401311 |. 50 push eax ; |Buffer = NULL
00401312 |. 68 E9030000 push 0x3E9 ; |ControlID = 3E9 (1001.)
00401317 |. 53 push ebx ; |hWnd = NULL
00401318 |. FFD6 call esi ; \GetDlgItemTextA
0040131A |. 68 00010000 push 0x100 ; /Count = 100 (256.)
0040131F |. 8D85 C0FDFFFF lea eax,[local.144] ; |
00401325 |. 50 push eax ; |Buffer = NULL
00401326 |. 68 EA030000 push 0x3EA ; |ControlID = 3EA (1002.)
0040132B |. 53 push ebx ; |hWnd = NULL
0040132C |. FFD6 call esi ; \GetDlgItemTextA
显然是在获取我输入的信息,所以我就在0040132E 这里下断,看看如何处理我输入的数据。
3.F2在0040132E 这里下断点后,邮箱输入778899@qq.com,序列号输入778899,然后点击OK,断了下来,开始单步跟踪
0040132E |. 8D85 C0FCFFFF lea eax,[local.208] ; 取邮箱778899@qq.com
00401334 |. 68 380A4100 push 9d2361b3.00410A38 ; @
00401339 |. 50 push eax ; eax入栈
0040133A |. E8 E10D0000 call 9d2361b3.00402120 ; 检查邮箱格式是否正确
0040133F |. 83C4 08 add esp,0x8 ; 平衡堆栈
00401342 |. 85C0 test eax,eax ; 比较eax是否为0
00401344 |. 75 1E jnz short 9d2361b3.00401364 ; 不为0则跳转
00401346 |> 68 3C0A4100 push 9d2361b3.00410A3C ; Your E-mail address in not valid.
验证的过程没分析出来,反正不影响我们分析程序,这个call直接F8步过
4.我这里输入的是正常的邮箱,所以上面那个jnz会跳转,然后继续F8,后面的代码的也是类似的,暂时没什么头绪。
0x3上IDA
1.在OD分析的过程中,已经定位到了关键函数00401280,那么在IDA中找到这个函数,F5一下
BOOL __userpurge DialogFunc@<eax>(__m128i a1@<xmm0>, HWND hDlg, UINT a3, WPARAM a4, LPARAM a5)
{
HMODULE v6; // eax@31
HICON v7; // eax@31
HMODULE v8; // eax@31
HCURSOR v9; // ST20_4@31
HWND v10; // eax@31
CHAR String; // [sp+8h] [bp-340h]@5
CHAR v12[4]; // [sp+108h] [bp-240h]@5
char v13; // [sp+10Ch] [bp-23Ch]@21
char v14; // [sp+10Dh] [bp-23Bh]@23
char v15; // [sp+10Eh] [bp-23Ah]@25
char v16; // [sp+10Fh] [bp-239h]@27
char v17; // [sp+110h] [bp-238h]@28
char v18; // [sp+111h] [bp-237h]@26
char v19; // [sp+112h] [bp-236h]@24
char v20; // [sp+113h] [bp-235h]@22
char v21; // [sp+114h] [bp-234h]@20
char v22; // [sp+115h] [bp-233h]@18
char v23; // [sp+116h] [bp-232h]@16
char v24; // [sp+117h] [bp-231h]@14
CHAR Text; // [sp+208h] [bp-140h]@5
__int128 v26; // [sp+308h] [bp-40h]@11
__int128 v27; // [sp+318h] [bp-30h]@11
int v28; // [sp+328h] [bp-20h]@11
__int128 v29; // [sp+32Ch] [bp-1Ch]@11
int v30; // [sp+33Ch] [bp-Ch]@11
__int16 v31; // [sp+340h] [bp-8h]@11
if ( a3 == 16 )
{
EndDialog(hDlg, 0);
return 0;
}
if ( a3 == 272 )
{
v6 = GetModuleHandleW(0);
v7 = LoadIconW(v6, (LPCWSTR)0x67);
SetClassLongA(hDlg, -14, (LONG)v7);
v8 = GetModuleHandleW(0);
v9 = LoadCursorW(v8, (LPCWSTR)0x66);
v10 = GetDlgItem(hDlg, 1);
SetClassLongA(v10, -12, (LONG)v9);
return 1;
}
if ( a3 != 273 || (unsigned __int16)a4 != 1 )
return 0;
sub_402710(&String, a4 - 1, 256);
sub_402710(v12, 0, 256);
sub_402710(&Text, 0, 256);
GetDlgItemTextA(hDlg, 1001, &String, 256);
GetDlgItemTextA(hDlg, 1002, v12, 256);
if ( sub_402120(a1, (int)&String, (const __m128i *)&unk_410A38)
&& sub_402120(a1, (int)&String, (const __m128i *)".")
&& *(_BYTE *)(sub_402120(a1, (int)&String, (const __m128i *)".") + 1)
&& *(_BYTE *)(sub_402120(a1, (int)&String, (const __m128i *)&unk_410A38) + 1) != 46 )
{
v29 = xmmword_410AA0;
v30 = 1701999980;
v26 = xmmword_410A90;
v31 = 46;
v27 = xmmword_410A80;
v28 = 3830633;
if ( strlen(v12) != 16
|| v12[0] != 67
|| v24 != 88
|| v12[1] != 90
|| v12[1] + v23 != 155
|| v12[2] != 57
|| v12[2] + v22 != 155
|| v12[3] != 100
|| v21 != 55
|| v13 != 109
|| v20 != 71
|| v14 != 113
|| v14 + v19 != 170
|| v15 != 52
|| v18 != 103
|| v16 != 99
|| v17 != 56 )
{
sub_4030C7(&Text, 256, &v29);
}
else
{
sub_4030C7(&Text, 256, &v26);
sub_403121(&Text, 256, v12);
}
}
else
{
sub_4030C7(&Text, 256, "Your E-mail address in not valid.");
}
MessageBoxA(hDlg, &Text, "Registeration", 0x40u);
return 1;
}
2.外层if显然是判断邮件地址是否正确,不需要管他,去看里面的那一个if,根据经验知道必须满足if才是正确流程,接下来就分析这些代码的作用。
GetDlgItemTextA(hDlg, 1001, &String, 256);//邮箱
GetDlgItemTextA(hDlg, 1002, v12, 256);//用户名
这两行是将输入框的内容存入String和v12中,知道了两个重要变量的含义,我就直接去分析if里面的那一个if。
v29 = xmmword_410AA0;
v30 = 1701999980;
v26 = xmmword_410A90;
v31 = 46;
v27 = xmmword_410A80;
v28 = 3830633;
上面这几行数据定义是不是有点懵,那么再看下之前在OD中看到的:
004013B0 |. 0F2805 A00A41>movaps xmm0,dqword ptr ds:[0x410AA0] ; Registration fai
004013B7 |. 8D8D C0FDFFFF lea ecx,[local.144]
004013BD |. 0F1145 E4 movups dqword ptr ss:[ebp-0x1C],xmm0
004013C1 |. 8D51 01 lea edx,dword ptr ds:[ecx+0x1]
004013C4 |. C745 F4 6C757>mov [local.3],0x6572756C
004013CB |. 0F2805 900A41>movaps xmm0,dqword ptr ds:[0x410A90] ; Registration SucRegistration fai
004013D2 |. 0F1145 C0 movups dqword ptr ss:[ebp-0x40],xmm0
004013D6 |. 66:C745 F8 2E>mov word ptr ss:[ebp-0x8],0x2E
004013DC |. 0F2805 800A41>movaps xmm0,dqword ptr ds:[0x410A80] ; cess!\nYour flag Registration SucRegistration fai
004013E3 |. 0F1145 D0 movups dqword ptr ss:[ebp-0x30],xmm0
可以知道[0x410AA0] 存储的是Registration fai,[0x410A90] 存储的是Registration SucRegistration fai,[0x410A80] 存储的是cess!\nYour flag Registration SucRegistration fai。
3.变量定义清楚了,接下来就去看看if中的条件。
if (strlen(v12) != 16 //序列号长度要等于16
|| v12[0] != 67 //第一个字符要为字母C
|| v24 != 88 //v24要为字母X
|| v12[1] != 90 //第二个字符要为字母Z
|| v12[1] + v23 != 155 //v23要为字母A
|| v12[2] != 57 //第三个字符要为数字9
|| v12[2] + v22 != 155 //v22要为字母b
|| v12[3] != 100 //第四个字符要为字母d
|| v21 != 55 //v21要为数字7
|| v13 != 109 //v13要为字母m
|| v20 != 71 //v20要为字母G
|| v14 != 113 //v14要为字母q
|| v14 + v19 != 170 //v19要为数字9
|| v15 != 52 //v15要为数字4
|| v18 != 103 //v18要为字母g
|| v16 != 99 //v16要为字母c
|| v17 != 56) //v17要为字母8
看似把它拼起来就是flag,然而我只知道数组v12的四个字符分别为CZ9d,后面的V变量的值代表的是序列号中的哪几位呢?
4.去看看他们与v12的变量声明
CHAR v12[4]; // [sp+108h] [bp-240h]@5
char v13; // [sp+10Ch] [bp-23Ch]@21
char v14; // [sp+10Dh] [bp-23Bh]@23
char v15; // [sp+10Eh] [bp-23Ah]@25
char v16; // [sp+10Fh] [bp-239h]@27
char v17; // [sp+110h] [bp-238h]@28
char v18; // [sp+111h] [bp-237h]@26
char v19; // [sp+112h] [bp-236h]@24
char v20; // [sp+113h] [bp-235h]@22
char v21; // [sp+114h] [bp-234h]@20
char v22; // [sp+115h] [bp-233h]@18
char v23; // [sp+116h] [bp-232h]@16
char v24; // [sp+117h] [bp-231h]@14
esp+108是V12[0],esp+109是v12[1],esp+10A是v12[2],esp+10B是v12[3],esp+10C是v13......,按照这个存储顺序,依次类推就能得出flag:CZ9dmq4c8g9G7bAX
0x4总结
1.通过关键字符串搜索或messageBOX定位到关键函数
2.使用IDA对关键函数进行F5,分析关键函数
3.通过与OD对照,能让自己更加清晰的知道每个变量的值
4.通过堆栈结构和数据类型所占空间大小,得出字符串的正确顺序