逆向学习笔记(二)

这一篇文章主要是对程序中的循环结构做一个讲解,这三大基础的循环在逆向分析中十分重要,另外还有三个程序包括其源代码、汇编代码及其逆向过程做一个分析

补充一些指令及基础知识

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<stdio.h>
int main()
{
    int sum = 0;
    int count = 7;
    int index = 0;
    while( index <= count)       //循环替换部分
    {
        sum += index;
        index++;
    }                            //
    printf("%d\n",sum);

}

//以下为debug汇编代码,这里只需注意循环部分,连接处可能存在差异
//该处只解释循环部分汇编代码,其他部分下一个例子会有提及

1:#include<stdio.h>
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 <stdio.h>
2:#include <string.h>
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<cstdio>
2:#include<cmath>
3:#include<string>
4:#include<cstring>
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<char,std::char_traits<char>,std::allocator<char> >::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<char,std::char_traits<char>,std::allocator<char> >::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<cstdio>
2:#include<cstring>
3:#include<cmath>
4:#include<iostream>
5:#include<string>
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<char,std::char_traits<char>,std::allocator<char> >::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<char,std::char_traits<char>,std::allocator<char> >::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<char,std::char_traits<char>,std::allocator<char> >::~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<cstdio>
#include<cstring>
#include<string>
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版)》,大家如果有不会的就查书,希望可以对大家有所帮助,本篇文章如有错误,请留言。

猜你喜欢

转载自blog.csdn.net/life_hes_az/article/details/78595770