这一篇文章主要是对程序中的循环结构做一个讲解,这三大基础的循环在逆向分析中十分重要,另外还有三个程序包括其源代码、汇编代码及其逆向过程做一个分析
补充一些指令及基础知识
imul src 带符号乘
idiv src 带符号除
mul src
div src
dec dest 自减
inc dest 自加
int 中断指令
call dword ptr [eax+5] //eax = 1000h eax+5 = 1005h 当两个操作数的宽度不一样时,就要用到ptr
call dword ptr [<&API>] //执行一个系统API
cmp dest,src //该指令是比较指令,可以当成dest-src ,该操作不改变当前值,只改变标志位的值(zf)
movsx dest,src //带符号扩展,并传送
lea (Load effect address)取有效地址,也就是取偏移地址
操作符 offert :取得标号的偏移地址
mov ax,offert start ;相当于 mov ax,0
变量与常量相加的区别
两常数相加是,编译器在编译期间就计算出了两常数相加后的结果
有变量参加的加法,会先取出内存中的数据放入寄存器中,再通过add完成计算结果,最后在存回内存中
三大基础的循环
do{}while,while,for,是编程语言中通用的循环,在逆向中对于循环的识别是相当重要的
下面就利用一段简单的代码(累加),来了解三种循环
#include
int main()
{
int sum = 0;
int count = 7;
int index = 0;
while( index <= count) //循环替换部分
{
sum += index;
index++;
} //
printf("%d\n",sum);
}
//以下为debug汇编代码,这里只需注意循环部分,连接处可能存在差异
//该处只解释循环部分汇编代码,其他部分下一个例子会有提及
1:#include
2:int main()
3:{
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,4Ch
00401016 push ebx
00401017 push esi
00401018 push edi
00401019 lea edi,[ebp-4Ch] //edi = ebp-4Ch 相当于mov edi,ebp sub edi,4Ch
0040101C mov ecx,13h
00401021 mov eax,0CCCCCCCCh
00401026 rep stos dword ptr [edi]
4:int sum = 0;
00401028 mov dword ptr [ebp-4],0
5:int count = 7;
0040102F mov dword ptr [ebp-8],7
6:int index = 0;
00401036 mov dword ptr [ebp-0Ch],0
======================================
do{}while循环
======================================
7: do
8: {
9:sum += index;
0040103D mov eax,dword ptr [ebp-4]
00401040 add eax,dword ptr [ebp-0Ch]
00401043 mov dword ptr [ebp-4],eax
10: index++;
00401046 mov ecx,dword ptr [ebp-0Ch]
00401049 add ecx,1
0040104C mov dword ptr [ebp-0Ch],ecx
11: }while(index <= count);
0040104F mov edx,dword ptr [ebp-0Ch]
00401052 cmp edx,dword ptr [ebp-8] //比较两个数据
00401055 jle main+2Dh (0040103d) //根据比较结果,判断是否跳出,jle小于等于则跳出、
========================================
while循环
========================================
7:while( index <= count)
0040103D mov eax,dword ptr [ebp-0Ch] //条件判断,jg指令表示大于count,则跳转到00401059h
00401040 cmp eax,dword ptr [ebp-8]
00401043 jg main+49h (00401059) //即直接跳出循环(00401059h为循环外的地址)
8:{
9:sum += index;
00401045 mov ecx,dword ptr [ebp-4]
00401048 add ecx,dword ptr [ebp-0Ch]
0040104B mov dword ptr [ebp-4],ecx
10: index++;
0040104E mov edx,dword ptr [ebp-0Ch]
00401051 add edx,1
00401054 mov dword ptr [ebp-0Ch],edx
11: }
00401057 jmp main+2Dh (0040103d) //跳转到0040103d
========================================
for循环
=========================================
7:for(index = 0;index < count;index ++) 1.赋初值
0040103D mov dword ptr [ebp-0Ch],0 初始化计数器变量index
00401044 jmp main+3Fh (0040104f) 跳转到0040104f处,跳过步长操作
00401046 mov eax,dword ptr [ebp-0Ch] 2.步长计算
00401049 add eax,1 // 步长值加1
0040104C mov dword ptr [ebp-0Ch],eax 步长值放入计数器变量i中
0040104F mov ecx,dword ptr [ebp-0Ch]
00401052 cmp ecx,dword ptr [ebp-8] 3.条件比较部分
00401055 jge main+52h (00401062) //比较后,大于count则跳转
8:{
9:sum += index;
00401057 mov edx,dword ptr [ebp-4]
0040105A add edx,dword ptr [ebp-0Ch]
0040105D mov dword ptr [ebp-4],edx
10: }
00401060 jmp main+36h (00401046)
========================================
12:
13: printf("%d\n",sum);
0040104E mov edx,dword ptr [ebp-4]
00401051 push edx
00401052 push offset string "%d\n" (0042201c)
00401057 call printf (004010a0)
0040105C add esp,8
14:
15: }
0040105F pop edi
00401060 pop esi
00401061 pop ebx
00401062 add esp,4Ch
00401065 cmp ebp,esp
00401067 call__chkesp (00401120)
0040106C mov esp,ebp
0040106E pop ebp
0040106F ret
do{}while();循环执行效率最高,只用了一次跳转,编译器对循环进行优化是使用if单分支结构进行第一次执行循环的判断,以此来减少跳转指令。
栈结构在内存中占用一段连续的储存空间,ebp == esp 栈平衡,当ebp > esp时,就形成了栈帧
函数调用
参数的传递:通过栈或寄存器的方式传递参数
函数调用,将返回地址压入栈中:使用call指令调用参数,并将返回地址压入栈中(这一点在栈溢出的方面会详细介绍)
数组:以线性方式连续储存在内存中的一段相同数据类型的数据集合(数组名是一个地址常量值,保存数组首元素地址)字符串可以当做一个数组,函数中是通过数组/字符串的首地址(以指针的方式进行传递)来调用,函数参数中保存的是数组的首地址,是一个指针变量
字符串以 ‘\0’结尾,ida 中使用A来分析字符串的首地址
以下是是我写的三道题,并附上了c代码和其汇编代码,对于一些语句做了注释,每道题后都有逆向它的过程,程序虽然简单,但对于熟悉逆向的过程是有好处的
一段代码(creakme_1)
1:#include
2:#include
3:#define PASSWORD "Fuck_50_ea5y!"
4:int verify_password (char *password)
5:{
00401020 push ebp //保存栈底指针ebp
00401021 mov ebp,esp
00401023 sub esp,48h //调高栈顶esp,开辟出48h的栈空间,为局部变量
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-48h] //取出此函数可用栈空间首地址放入edi
0040102C mov ecx,12h
00401031 mov eax,0CCCCCCCCh //局部变量初始化
00401036 rep stos dword ptr [edi] //根据ecx的值,将eax中的内容,以dw为单位写到edi指向的内存中
6:int n;
7:for (int i = 0;i < 13;i++)
========================================== 1.赋初值
00401038 mov dword ptr [ebp-8],0 //初始化计数器变量i
0040103F jmp verify_password+2Ah (0401040a) //跳转到0401040a处,跳过步长操作
========================================== 2.步长计算
00401041 mov eax,dword ptr [ebp-8]
00401044 add eax,1 // 步长值加1
00401047 mov dword ptr [ebp-8],eax 步长值放入计数器变量i中
========================================== 3.条件比较部分
0040104A cmp dword ptr [ebp-8],0Dh
0040104E jge verify_password+62h (00401082) //比较后,大于常数则跳转
==========================================
;for循环内部执行块
8:{
9:if(password[i] == 'o')
00401050 mov ecx,dword ptr [ebp+8]
00401053 add ecx,dword ptr [ebp-8]
00401056 movsx edx,byte ptr [ecx]
00401059 cmp edx,6Fh // 判断是否相等
0040105C jne verify_password+49h (00401069) //根据zf==0,!=0就跳
10: password[i] = '0';
0040105E mov eax,dword ptr [ebp+8]
00401061 add eax,dword ptr [ebp-8]
00401064 mov byte ptr [eax],30h
11: else if(password[i] == 's')
00401067 jmp verify_password+60h (00401080) //直接跳转到00401080,跳转到多个分支结构的结尾地址
00401069 mov ecx,dword ptr [ebp+8]
0040106C add ecx,dword ptr [ebp-8]
0040106F movsx edx,byte ptr [ecx]
00401072 cmp edx,73h
00401075 jne verify_password+60h (00401080)
12: password[i] = '5';
00401077 mov eax,dword ptr [ebp+8]
0040107A add eax,dword ptr [ebp-8]
0040107D mov byte ptr [eax],35h
13:
14: }
00401080 jmp verify_password+21h (00401041)
15:
16: n = strcmp(password,PASSWORD); //获取常量的首地址,并将此地址压入栈中作为strcpy参数
00401082 push offset string "Fuck_50_ea5y!" (0042501c)
00401087 mov ecx,dword ptr [ebp+8]
0040108A push ecx
0040108B call strcmp (004011a0)
00401090 add esp,8
00401093 mov dword ptr [ebp-4],eax
17: return n;
00401096 mov eax,dword ptr [ebp-4]
18: }
//以下是函数退出时的代码
00401099 pop edi
0040109A pop esi
0040109B pop ebx
0040109C add esp,48h //降低栈顶esp,释放局部变量空间
0040109F cmp ebp,esp //检测栈平衡,
004010A1 call__chkesp (00401230) //进入栈平衡错误检测函数
004010A6 mov esp,ebp
004010A8 pop ebp
004010A9 ret
/*
*/
19:
20: main()
21: {
004010D0 push ebp
004010D1 mov ebp,esp
004010D3 sub esp,444h
004010D9 push ebx
004010DA push esi
004010DB push edi
004010DC lea edi,[ebp-444h]
004010E2 mov ecx,111h
004010E7 mov eax,0CCCCCCCCh
004010EC rep stos dword ptr [edi]
22: int valid_flag=0;
004010EE mov dword ptr [ebp-4],0
23: char password[1024];
24: while(1)
004010F5 mov eax,1
004010FA test eax,eax
004010FC je main+87h (00401157) //条件判断比较,判断是否跳转(与通常的while不同,由于这是死循环)
25: {
26: printf("please input password:");
004010FE push offset string "please input password:" (00425064)
00401103 call printf (004012d0)
00401108 add esp,4
27: scanf("%s",password);
0040110B lea ecx,[ebp-404h]
00401111 push ecx
00401112 push offset string "%s" (00425060)
00401117 call scanf (00401270)
0040111C add esp,8
28: valid_flag = verify_password(password);
0040111F lea edx,[ebp-404h]
00401125 push edx
00401126 call @ILT+0(verify_password) (00401005) //调用函数
0040112B add esp,4
0040112E mov dword ptr [ebp-4],eax
29: if(valid_flag)
00401131 cmp dword ptr [ebp-4],0
00401135 je main+76h (00401146)
30: {
31: printf("incorrect password!\n\n");
00401137 push offset string "incorrect password!\n\n" (00425044)
0040113C call printf (004012d0)
00401141 add esp,4
32: }
33: else
00401144 jmp main+85h (00401155)
34: {
35: printf("Congratulation! \n");
00401146 push offset string "Congratulation! \n" (0042502c)
0040114B call printf (004012d0)
00401150 add esp,4
36: break;
00401153 jmp main+87h (00401157)
37: }
38: }
00401155 jmp main+25h (004010f5)
39: }
00401157 pop edi
00401158 pop esi
00401159 pop ebx
0040115A add esp,444h //降低栈顶esp,释放局部变量空间
00401160 cmp ebp,esp //检测栈平衡,
00401162 call__chkesp (00401230) //进入栈平衡错误检测函数
00401167 mov esp,ebp
00401169 pop ebp
0040116A ret
使用ida去分析程序,如果对一些汇编代码不熟,建议从od开始学习,动态调试工具可以更好地去熟悉。
找到main函数
分析一下,重点在 Z15verify_passwordPc 函数,以下简称password
分析完了,f5得到c伪代码
观察一下,得到flag
crackme_2
00401064 jmp yy (00401220)
1:#include
2:#include
3:#include
4:#include
5:using namespace std;
6:int flag = 1;
7:int a[16] = {21,27,20,28,19,101,9,3,5,108,84,44,57,84,26,15};
8:string k = "flag{Th1s_1s_!true}";
00401140 push ebp
00401141 mov ebp,esp
00401143 sub esp,44h
00401146 push ebx
00401147 push esi
00401148 push edi
00401149 lea edi,[ebp-44h]
0040114C mov ecx,11h
00401151 mov eax,0CCCCCCCCh
00401156 rep stos dword ptr [edi]
00401158 lea eax,[ebp-4]
0040115B push eax
0040115C push offset string "flag{Th1s_1s_!true}" (0042901c)
00401161 mov ecx,offset k (0042f0b0)
00401166 call @ILT+115(std::basic_string,std::allocator >::basic_str
0040116B pop edi
0040116C pop esi
0040116D pop ebx
0040116E add esp,44h
00401171 cmp ebp,esp
00401173 call__chkesp (00402820)
00401178 mov esp,ebp
0040117A pop ebp
0040117B ret
/*
*/
9: void yy(char *x)
10: {
00401220 push ebp
00401221 mov ebp,esp
00401223 sub esp,44h
00401226 push ebx
00401227 push esi
00401228 push edi
00401229 lea edi,[ebp-44h]
0040122C mov ecx,11h
00401231 mov eax,0CCCCCCCCh
00401236 rep stos dword ptr [edi]
11: for(int i = 0;i < 16;i++)
00401238 mov dword ptr [ebp-4],0
0040123F jmp yy+2Ah (0040124a)
00401241 mov eax,dword ptr [ebp-4]
00401244 add eax,1
00401247 mov dword ptr [ebp-4],eax
0040124A cmp dword ptr [ebp-4],10h
0040124E jge yy+56h (00401276)
12: {
13: x[i] = x[i] ^ k[i];
00401250 mov ecx,dword ptr [ebp+8]
00401253 add ecx,dword ptr [ebp-4]
00401256 movsx ebx,byte ptr [ecx]
00401259 mov edx,dword ptr [ebp-4]
0040125C push edx
0040125D mov ecx,offset k (0042f0b0)
00401262 call @ILT+55(std::basic_string,std::allocator >::operator[]
00401267 movsx eax,byte ptr [eax]
0040126A xor ebx,eax
0040126C mov ecx,dword ptr [ebp+8]
0040126F add ecx,dword ptr [ebp-4]
00401272 mov byte ptr [ecx],bl
14: }
00401274 jmp yy+21h (00401241)
15:
16: }
00401276 pop edi
00401277 pop esi
00401278 pop ebx
00401279 add esp,44h
0040127C cmp ebp,esp
0040127E call__chkesp (00402820)
00401283 mov esp,ebp
00401285 pop ebp
00401286 ret
/*
*/
17:
18: int main()
19: {
004012A0 push ebp
004012A1 mov ebp,esp
004012A3 sub esp,0A8h
004012A9 push ebx
004012AA push esi
004012AB push edi
004012AC lea edi,[ebp-0A8h]
004012B2 mov ecx,2Ah
004012B7 mov eax,0CCCCCCCCh
004012BC rep stos dword ptr [edi]
20: char v[100];
21: printf("Please input flag:");
004012BE push offset string "Please input flag:" (00429054)
004012C3 call printf (00402a60)
004012C8 add esp,4
22: scanf("%s",v);
004012CB lea eax,[ebp-64h]
004012CE push eax
004012CF push offset string "%s" (00429050)
004012D4 call scanf (00402a00)
004012D9 add esp,8
23: if(strlen(v) == 16)
004012DC lea ecx,[ebp-64h]
004012DF push ecx
004012E0 call strlen (00402980)
004012E5 add esp,4
004012E8 cmp eax,10h
004012EB jne main+0BAh (0040135a)
24: {
25: yy(v);
004012ED lea edx,[ebp-64h]
004012F0 push edx
004012F1 call @ILT+95(yy) (00401064)
004012F6 add esp,4
26: for(int i = 0;i < 16;i++)
004012F9 mov dword ptr [i],0
00401300 jmp main+6Bh (0040130b)
00401302 mov eax,dword ptr [i]
00401305 add eax,1
00401308 mov dword ptr [i],eax
0040130B cmp dword ptr [i],10h
0040130F jge main+93h (00401333)
27: {
28: if((int)v[i] != a[i])
00401311 mov ecx,dword ptr [i]
00401314 movsx edx,byte ptr [ebp+ecx-64h]
00401319 mov eax,dword ptr [i]
0040131C cmp edx,dword ptr [eax*4+42BD54h]
00401323 je main+91h (00401331)
29: {
30: flag = 0;
00401325 mov dword ptr [flag (0042bd50)],0
31: break;
0040132F jmp main+93h (00401333)
32: }
33: }
00401331 jmp main+62h (00401302)
34: if(flag)
00401333 cmp dword ptr [flag (0042bd50)],0
0040133A je main+0ABh (0040134b)
35: printf("成功了!\n");
0040133C push offset string "\xb3\xc9\xb9\xa6\xc1\xcb\xa3\xa1\n" (00429044)
00401341 call printf (00402a60)
00401346 add esp,4
36: else
00401349 jmp main+0B8h (00401358)
37: printf("Tryagain!\n");
0040134B push offset string "Tryagain!\n" (00429034)
00401350 call printf (00402a60)
00401355 add esp,4
38:
39: }
40: else
00401358 jmp main+0C7h (00401367)
41: printf("Tryagain!\n");
0040135A push offset string "Tryagain!\n" (00429034)
0040135F call printf (00402a60)
00401364 add esp,4
42:
43: return 0;
00401367 xor eax,eax
44: }
00401369 pop edi
0040136A pop esi
0040136B pop ebx
0040136C add esp,0A8h
00401372 cmp ebp,esp
00401374 call __chkesp (00402820)
00401379 mov esp,ebp
0040137B pop ebp
0040137C ret
分析
ida中 var_表示局部变量
f5一下
进入yy()函数
从汇编代码中找到异或后比较的数组
与之异或的字符串
整理一下思路,输入一段字符串与程序内一字符串异或后与a1[]相比,相等及成功。(因为程序内的字符串和数组定义在函数外,增加了逆向难度)
reverse
1:#include
2:#include
3:#include
4:#include
5:#include
6:using namespace std;
7:int main()
8:{
004010F0 push ebp
004010F1 mov ebp,esp
004010F3 push 0FFh
004010F5 push offset __ehhandler$_main (004216ec)
004010FA mov eax,fs:[00000000]
00401100 push eax
00401101 mov dword ptr fs:[0],esp
00401108 sub esp,4CCh
0040110E push ebx
0040110F push esi
00401110 push edi
00401111 lea edi,[ebp-4D8h]
00401117 mov ecx,133h
0040111C mov eax,0CCCCCCCCh
00401121 rep stos dword ptr [edi]
9:int v11 = 24;
00401123 mov dword ptr [ebp-10h],18h
10: int v3 = 1;
0040112A mov dword ptr [ebp-14h],1
11: int v2[] = {31,102,14,97,48,123,57,95,32,95,39,95,16,95,7,116,29,65,26,100,84,48,15,100};
00401131 mov dword ptr [ebp-74h],1Fh
00401138 mov dword ptr [ebp-70h],66h
0040113F mov dword ptr [ebp-6Ch],0Eh
00401146 mov dword ptr [ebp-68h],61h
0040114D mov dword ptr [ebp-64h],30h
00401154 mov dword ptr [ebp-60h],7Bh
0040115B mov dword ptr [ebp-5Ch],39h
00401162 mov dword ptr [ebp-58h],5Fh
00401169 mov dword ptr [ebp-54h],20h
00401170 mov dword ptr [ebp-50h],5Fh
00401177 mov dword ptr [ebp-4Ch],27h
0040117E mov dword ptr [ebp-48h],5Fh
00401185 mov dword ptr [ebp-44h],10h
0040118C mov dword ptr [ebp-40h],5Fh
00401193 mov dword ptr [ebp-3Ch],7
0040119A mov dword ptr [ebp-38h],74h
004011A1 mov dword ptr [ebp-34h],1Dh
004011A8 mov dword ptr [ebp-30h],41h
004011AF mov dword ptr [ebp-2Ch],1Ah
004011B6 mov dword ptr [ebp-28h],64h
004011BD mov dword ptr [ebp-24h],54h
004011C4 mov dword ptr [ebp-20h],30h
004011CB mov dword ptr [ebp-1Ch],0Fh
004011D2 mov dword ptr [ebp-18h],64h
12: string k = "sicnuisasher";
004011D9 lea eax,[ebp-498h]
004011DF push eax
004011E0 push offset string "sicnuisasher" (00433064)
004011E5 lea ecx,[ebp-84h]
004011EB call @ILT+110(std::basic_string,std::allocator >::basic_str //调用函数
004011F0 mov dword ptr [ebp-4],0
13: char s[1024];
14: int v8 = 0;
004011F7 mov dword ptr [ebp-488h],0
15: int i;
16: do{
17: printf("flag's:");
00401201 push offset string "flag's:" (00433058)
00401206 call printf (00408b50)
0040120B add esp,4
18: scanf("%s",s);
0040120E lea ecx,[ebp-484h]
00401214 push ecx
00401215 push offset string "%s" (00433054)
0040121A call scanf (00408af0)
0040121F add esp,8
19: int b = strlen(s);
00401222 lea edx,[ebp-484h]
00401228 push edx
00401229 call strlen (00408a70)
0040122E add esp,4
00401231 mov dword ptr [b],eax
20: for(i = 0;i < b;i++)
00401237 mov dword ptr [ebp-48Ch],0
00401241 jmp main+162h (00401252)
00401243 mov eax,dword ptr [ebp-48Ch]
00401249 add eax,1
0040124C mov dword ptr [ebp-48Ch],eax
00401252 mov ecx,dword ptr [ebp-48Ch]
00401258 cmp ecx,dword ptr [b]
0040125E jge main+1D8h (004012c8)
21: {
22: if(v8 == 12) break;
00401260 cmp dword ptr [ebp-488h],0Ch
00401267 jne main+17Bh (0040126b)
00401269 jmp main+1D8h (004012c8)
23: if(i % 2 != 0)
0040126B mov edx,dword ptr [ebp-48Ch]
00401271 and edx,80000001h
00401277 jns main+18Eh (0040127e)
00401279 dec edx
0040127A or edx,0FEh
0040127D inc edx
0040127E test edx,edx
00401280 je main+1D3h (004012c3)
24: {
25: s[i] = ((char)(s[i] ^ k[v8]));
00401282 mov eax,dword ptr [ebp-48Ch]
00401288 movsx ebx,byte ptr [ebp+eax-484h]
00401290 mov ecx,dword ptr [ebp-488h]
00401296 push ecx
00401297 lea ecx,[ebp-84h]
0040129D call @ILT+55(std::basic_string,std::allocator >::operator[]
004012A2 movsx edx,byte ptr [eax]
004012A5 xor ebx,edx
004012A7 mov eax,dword ptr [ebp-48Ch]
004012AD mov byte ptr [ebp+eax-484h],bl
26: ++v8;
004012B4 mov ecx,dword ptr [ebp-488h]
004012BA add ecx,1
004012BD mov dword ptr [ebp-488h],ecx
27: }
28:
29: }
004012C3 jmp main+153h (00401243)
30: for(i = 0;i < b;i++)
004012C8 mov dword ptr [ebp-48Ch],0
004012D2 jmp main+1F3h (004012e3)
004012D4 mov edx,dword ptr [ebp-48Ch]
004012DA add edx,1
004012DD mov dword ptr [ebp-48Ch],edx
004012E3 mov eax,dword ptr [ebp-48Ch]
004012E9 cmp eax,dword ptr [b]
004012EF jge main+25Ah (0040134a)
31: {
32: if(i % 2 == 0)
004012F1 mov ecx,dword ptr [ebp-48Ch]
004012F7 and ecx,80000001h
004012FD jns main+214h (00401304)
004012FF dec ecx
00401300 or ecx,0FEh
00401303 inc ecx
00401304 test ecx,ecx
00401306 jne main+258h (00401348)
33: {
34: char v0 = s[i];
00401308 mov edx,dword ptr [ebp-48Ch]
0040130E mov al,byte ptr [ebp+edx-484h]
00401315 mov byte ptr [v0],al
35: s[i] = s[i+1];
0040131B mov ecx,dword ptr [ebp-48Ch]
00401321 mov edx,dword ptr [ebp-48Ch]
00401327 mov al,byte ptr [ebp+edx-483h]
0040132E mov byte ptr [ebp+ecx-484h],al
36: s[i+1] = v0;
00401335 mov ecx,dword ptr [ebp-48Ch]
0040133B mov dl,byte ptr [v0]
00401341 mov byte ptr [ebp+ecx-483h],dl
37: }
38: }
00401348 jmp main+1E4h (004012d4)
39: i = 0;
0040134A mov dword ptr [ebp-48Ch],0
40: while(i < b)
00401354 mov eax,dword ptr [ebp-48Ch]
0040135A cmp eax,dword ptr [b]
00401360 jge main+2BAh (004013aa)
41: {
42: if(b != v11) v3 = 0;
00401362 mov ecx,dword ptr [b]
00401368 cmp ecx,dword ptr [ebp-10h]
0040136B je main+286h (00401376)
0040136D mov dword ptr [ebp-14h],0
43: else if(s[i] != v2[i]) v3 = 0;
00401374 jmp main+2BAh (004013aa)
00401376 mov edx,dword ptr [ebp-48Ch]
0040137C movsx eax,byte ptr [ebp+edx-484h]
00401384 mov ecx,dword ptr [ebp-48Ch]
0040138A cmp eax,dword ptr [ebp+ecx*4-74h]
0040138E je main+2A9h (00401399)
00401390 mov dword ptr [ebp-14h],0
44: else{
00401397 jmp main+2BAh (004013aa)
45: ++i;
00401399 mov edx,dword ptr [ebp-48Ch]
0040139F add edx,1
004013A2 mov dword ptr [ebp-48Ch],edx
46: continue;
004013A8 jmp main+264h (00401354)
47: }
48: break;
49: }
50: if(v3 == 0)
004013AA cmp dword ptr [ebp-14h],0
004013AE jne main+2CFh (004013bf)
51: printf("Tryagain!\n");
004013B0 push offset string "Tryagain!\n" (00433044)
004013B5 call printf (00408b50)
004013BA add esp,4
52: else
004013BD jmp main+2DCh (004013cc)
53: {
54: printf("Congratulation! This is true.\n");
004013BF push offset string "Congratulation! This is true.\n" (0043301c)
004013C4 call printf (00408b50)
004013C9 add esp,4
55: }
56: }while(v3 == 0);
004013CC cmp dword ptr [ebp-14h],0
004013D0 je main+111h (00401201)
57:
58: }
004013D6 mov dword ptr [ebp-4],0FFFFFFFFh
004013DD lea ecx,[ebp-84h]
004013E3 call @ILT+75(std::basic_string,std::allocator >::~basic_str
004013E8 mov ecx,dword ptr [ebp-0Ch]
004013EB mov dword ptr fs:[0],ecx
004013F2 pop edi
004013F3 pop esi
004013F4 pop ebx
004013F5 add esp,4D8h
004013FB cmp ebp,esp
004013FD call__chkesp (00408fb0)
00401402 mov esp,ebp
00401404 pop ebp
00401405 ret
f5结果
看一下failure:4013F7:call analysis falied
到4013F7
修正一下
未知的就是v6[]数组里面的内容了
看看汇编代码发现
点进去,修改一下
根据以上分析,梳理一下程序执行的过程:要求输入一个字符串s,将其奇数位与程序内的一个字符串进行异或,然后再将奇数位和偶数位交换,再去与程序内的一个数组相比较,如果相同则正确。
把算法反过来,先交换,再异或,然后将其中没有声明的变量声明一下,运行,直接跑出flag.
#include
#include
#include
using namespace std;
int main()
{
int j = 0;
int v2[24]={31,102,14,97,48,123,57,95,32,95,39,95,16,95,7,116,29,65,26,100,84,48,15,100};
string k = "sicnuisasher";
for(int i = 0;i < 24;i++)
{
if(i % 2 == 0)
{
int v = v2[i];
v2[i] = v2[i+1];
v2[i+1] = v;
}
}
for(int i = 0;i < 24;i++)
{
if(i % 2 != 0)
{
v2[i] = ((int)(v2[i] ^ k[j]));
j++;
}
}
for(int i = 0;i < 24;i++)
printf("%c",v2[i]);
return 0;
}
本篇文章中用到的ida 是一款相当强大的逆向工具,掌握起来也较困难,推荐一本书《IDA Pro权威指南 (第2版)》,大家如果有不会的就查书,希望可以对大家有所帮助,本篇文章如有错误,请留言。