学破解第83天,《攻防世界reverse新手练习区csaw2013reversing2分析》
本帖最后由 小菜鸟一枚 于 2020-2-12 14:28 编辑# 学破解第83天,《攻防世界reverse新手练习区csaw2013reversing2分析》
前言:
一直对黑客充满了好奇,觉得黑客神秘,强大,无所不能,来论坛两年多了,天天看各位大佬发帖,自己只能做一个伸手党。也看了官方的入门视频教程,奈何自己基础太差,看不懂。自我反思之下,决定从今天(2019年6月17日)开始定下心来,从简单的基础教程开始学习,希望能从照抄照搬,到能独立分析,能独立破解。
不知不觉学习了好几个月,发现自己离了教程什么都不会,不懂算法,不懂编程。随着破解学习的深入,楼主这个半吊子迷失了自我,日渐沉迷水贴装X,不能自拔。
** ==========申明:从第71天楼主开始水贴装X,帖子不再具有连续性,仅供参考,后续帖子为楼主YY专用贴!!!========== **
立帖为证!--------记录学习的点点滴滴
## 0x1查壳
1.丢进exeinfoPE查壳,Microsoft Visual C++ v.10 - 2010程序。
2.再看一下题目描述:听说运行就能拿到Flag,不过菜鸡运行的结果不知道为什么是乱码。
3.运行一下程序,提示如图!
## 0x2上IDA
1.将程序丢进IDA,找到main函数,F5转换一下:
```
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // ecx
CHAR *lpMem; //
HANDLE hHeap; //
hHeap = HeapCreate(0x40000u, 0, 0);
lpMem = (CHAR *)HeapAlloc(hHeap, 8u, MaxCount + 1);
memcpy_s(lpMem, MaxCount, &unk_409B10, MaxCount);
if ( sub_40102A() || IsDebuggerPresent() )
{
__debugbreak();
sub_401000(v3 + 4, lpMem);
ExitProcess(0xFFFFFFFF);
}
MessageBoxA(0, lpMem + 1, "Flag", 2u);
HeapFree(hHeap, 0, lpMem);
HeapDestroy(hHeap);
ExitProcess(0);
}
```
2.可以看到main函数比较简单,里面就一个if语句,然后就弹窗内容为 lpMem + 1!
3.接着去百度各个函数的意义:
HeapCreate:创建堆栈
HeapAlloc:在堆上分配内存
memcpy_s:内存拷贝函数
IsDebuggerPresent():检测调试器,成功返回1,失败返回0。
ExitProcess:退出进程
MessageBoxA:弹窗口
HeapFree:释放堆内存
HeapDestroy:销毁堆
4.我们理一下程序的执行流程:
第一步:把409B10这个地址内的数据复制给 lpMem。
第二步:执行if语句,sub_40102A()这个函数里面return 0;再加上我们直接运行程序,IsDebuggerPresent()返回值也是0。所以这个if里面的代码块是一定不会被执行的。
第三步:弹窗,此时弹出来的是乱码!
5. 所以我就可以猜测如果这个if执行,会不会就能输出正确的flag。if里面只有一个函数sub_401000,代码如下:
```
unsigned int __fastcall sub_401000(int a1, int a2)
{
int v2; // esi
unsigned int v3; // eax
unsigned int v4; // ecx
unsigned int result; // eax
v2 = dword_409B38;
v3 = a2 + 1 + strlen((const char *)(a2 + 1)) + 1;
v4 = 0;
result = ((v3 - (a2 + 2)) >> 2) + 1;
if ( result )
{
do
*(_DWORD *)(a2 + 4 * v4++) ^= v2;
while ( v4 < result );
}
return result;
}
```
a2是我们最开始的那个lpMem参数。
## 0x3上OD
1.将程序丢进OD,在左下角数据窗口中搜索一下给lpMem赋值的内容,看到“惶牸苎靖拖井夷珎屹摮赞摡铀競铀竟氉梯”。
2.接下来Ctrl+G定位0040102A 到这个函数,然后查看信息窗口调用来自00401083,再次定位过去,我们看到了:
```
00401083 .E8 A2FFFFFF call 0453d212.0040102A ;这个call直接返回0
00401088 .85C0 test eax,eax ;eax不为0则跳转
0040108A .75 0A jnz short 0453d212.00401096
0040108C .FF15 14604000 call dword ptr ds:[<&KERNEL32.IsDebugger>; [IsDebuggerPresent
00401092 .85C0 test eax,eax ;eax为0则跳转
00401094 .74 23 je short 0453d212.004010B9
00401096 >41 inc ecx
00401097 .41 inc ecx
00401098 .41 inc ecx
00401099 .41 inc ecx
0040109A .CC int3
0040109B .8B55 F4 mov edx,dword ptr ss: ;kernel32.7C839AD8
0040109E .E8 5DFFFFFF call 0453d212.00401000 /;对初始字符串解密处理
004010A3 .EB 4A jmp short 0453d212.004010EF ;退出程序
004010A5 .6A 02 push 0x2 ; /Style = MB_ABORTRETRYIGNORE|MB_APPLMODAL
004010A7 .68 20784000 push 0453d212.00407820 ; |Flag
004010AC .FF75 F4 push dword ptr ss: ; |Text = "U嬱冹SVWU鼖]婨鰼"
004010AF .6A 00 push 0x0 ; |hOwner = NULL
004010B1 .FF15 E4604000 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
004010B7 .EB 14 jmp short 0453d212.004010CD
004010B9 >6A 02 push 0x2 ; /Style = MB_ABORTRETRYIGNORE|MB_APPLMODAL
004010BB .68 20784000 push 0453d212.00407820 ; |Flag
004010C0 .8B45 F4 mov eax,dword ptr ss: ; |kernel32.7C839AD8
004010C3 .40 inc eax ; |
004010C4 .50 push eax ; |Text = 91CB4D30 ???
004010C5 .6A 00 push 0x0 ; |hOwner = NULL
004010C7 .FF15 E4604000 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
004010CD >FF75 F4 push dword ptr ss: ; /pMemory = kernel32.7C839AD8
004010D0 .6A 00 push 0x0 ; |Flags = 0
004010D2 .FF75 FC push dword ptr ss: ; |hHeap = NULL
004010D5 .FF15 08604000 call dword ptr ds:[<&KERNEL32.HeapFree>] ; \HeapFree
004010DB .8945 F8 mov dword ptr ss:,eax
004010DE .FF75 FC push dword ptr ss: ; /hHeap = NULL
004010E1 .FF15 0C604000 call dword ptr ds:[<&KERNEL32.HeapDestro>; \HeapDestroy
004010E7 .6A 00 push 0x0 ; /ExitCode = 0x0
004010E9 .FF15 00604000 call dword ptr ds:[<&KERNEL32.ExitProces>; \ExitProcess
004010EF >6A FF push -0x1 ; /ExitCode = 0xFFFFFFFF
004010F1 .FF15 00604000 call dword ptr ds:[<&KERNEL32.ExitProces>; \ExitProcess
```
3.看上面这段代码,我就知道需要在0040108A 或者00401094 这里改为jmp,跳转到0040109B 这里,前面有int3中断,得跳过它执行00401000这个call。
4.我们可以看到执行完这个call后,程序就退出了,所以我们需要跟进这个call,看看代码:
```
00401000/$56 push esi
00401001|.8B35 389B4000 mov esi,dword ptr ds: ;华梯
00401007|.8D42 01 lea eax,dword ptr ds: ;eax存储着解密后的flag
0040100A|.57 push edi ;eax+1
0040100B|.8D78 01 lea edi,dword ptr ds:
0040100E|>8A08 /mov cl,byte ptr ds:
00401010|.40 |inc eax
00401011|.84C9 |test cl,cl
00401013|.^ 75 F9 \jnz short 0453d212.0040100E
00401015|.2BC7 sub eax,edi
00401017|.C1E8 02 shr eax,0x2
0040101A|.33C9 xor ecx,ecx
0040101C|.40 inc eax
0040101D|.74 08 je short 0453d212.00401027
0040101F|>31348A /xor dword ptr ds:,esi
00401022|.41 |inc ecx
00401023|.3BC8 |cmp ecx,eax
00401025|.^ 72 F8 \jb short 0453d212.0040101F
00401027|>5F pop edi
00401028|.5E pop esi
00401029\.C3 retn
```
右侧的寄存器edi显示的是008F1E92,edi在eax的值上面加一了,所以在数据窗口中跟随向上翻或者看eax的值就能看到flag。
5.出了这个call之后,就退出程序了,因为上面那段代码有两个MessageBOX,我需要判断出来后jmp需要改跳到哪一个,所以去看看原程序,是从00401094 这里跳转到004010B9 这里弹窗,综上所述,需要修改两处为:
00401094 /74 23 je short 0453d212.0040109B
004010A3 /EB 4A jmp short 0453d212.004010B9
运行程序,弹出正确的flag!
## 0x4总结
1.IDA和OD结合使用,确定变量的值和程序的流程。
2. 把那个初始字符串加1弹出来的内容和原程序不一样
```
char arr[] = {0xBB,0xCC,0xA0,0xBC,0xDC,0xD1,0xBE,0xB8,0xCD,0xCF,0xBE,0xAE,0xD2,0xC4,0xAB,0x82,0xD2,
0xD9,0x93,0xB3,0xD4,0xDE,0x93,0xA9,0xD3,0xCB,0xB8,0x82,0xD3,0xCB,0xBE,0xB99A,0xD7,0xCC,0xDD,'\0'};
MessageBoxA(0, arr + 1, "Flag", 2u);
```
3.调用00401000时传入的两个参数不太明白,v3+4看不懂,后面一个传的好像是初始字符串。
4.00401000函数里面的那段解密过程也看不懂,希望有大佬不良赐教!
总结:楼主是个小菜鸟,离了教程啥都不会! 你可以想想这帮大牛是怎么崛起的。他那个年代破解视频少的可怜。他们不是照样学的很厉害。什么原因有想过吗。重点不在教程。而在于编程,你首先得会编程理解计算机是怎么运作的。有的为了反汇编一个程序,常常自己编个类似的程序分析原理。想学好的话还是先把基础打好吧 xvbwily 发表于 2020-2-13 08:39
入门课程从哪学起啊
学破解第71天,楼主学习记录导航贴更新(含学习资源和楼主全部学习记录)!:https://www.52pojie.cn/thread-1067012-1-1.html 加油,高手都是从菜鸟走过来的。 你将来不可限量 楼主已经比大多数人要强了 千里之行始于足下,愿我们都可以一步步走向强大! 希望这种通俗易懂的 对楼主莫大的鼓励和支持 你将来不可限量 感谢楼主分享
关注了 持续看准备学习