美文网首页Ethical Hackers网络安全实验室
汇编入门你应该知道的知识

汇编入门你应该知道的知识

作者: 蚁景科技 | 来源:发表于2020-06-23 14:13 被阅读0次

    160个CrackMe-001

    首先运行程序,发现程序是个注册机,输入用户名与注册码。

    点击Check it Baby!会检测注册码是否正确,并且多次尝试发现提示语句相同

    拉进OD进行分析,当弹出提示时不着急点确定,回到OD点击暂停运行按钮

    点击堆栈(crlt+k)或者小图标K

    找到地址为0042a1ae的MessageBoxA的函数,该函数为win32的弹窗函数,并且距离用户代码的入口点00401000非常接近

    右键->显示函数调用过程,观察那个函数调用了此函数,找到相关函数,可以发现这是MessageBox调用的过程,那么在堆栈区找到返回函数,观察该函数执行完会返回到哪个函数

    打下断点,运行到此处,在右下角的堆栈窗口查看返回地址,在堆栈窗口中右键->地址->相对于EBP,找到EBP+4的地址,对应的地址为返回地址,右键该地址,反汇编窗口跟随

    找到关键的跳转,该跳转会执行错误弹框信息。

    方法一:暴力破解

    由于该跳转是用JNZ实现的,那么将跳转改为JE或者NOP掉改变程序的执行流程

    (1)修改为JE,右键关键跳转语句->选择汇编

    此时成功信息弹出

    (2)用NOP填充,由于在关键的跳转语句下有个调用弹框函数,因此猜测该函数为成功的执行流。

    右键关键跳转,选择NOP填充

    同样弹出成功消息

    方法二:注册机算法

    发现在关键跳转前有个call调用,打下断点观察下寄存器的值

    在执行到该调用语句时,观察右上角的寄存器窗口,发现了疑似注册码的值,以及我们手动输入的注册码,两者进行比较若不相同则直接跳转到错误弹窗。

    将疑似注册码输入,发现成功弹窗,因此验证了这个就是注册码的值,那么在call语句实现之前则注册码已经生成

    0042FAF3的调用没有什么特殊的,跟进去0042FAE5的调用

    (0042FAE5调用)汇编代码

    此时可以看到,在进入0042FAE5调用之前,激活码已经生成完毕,在该函数调用只是进行了字符串的替换,将我们输入的name值分部分替换为激活码。

    004039AC   $ 53             PUSH EBX

    004039AD   . 56             PUSH ESI

    004039AE   . 52             PUSH EDX

    004039AF   . 50             PUSH EAX

    004039B0   . 89D3           MOV EBX,EDX

    004039B2   . 31C0           XOR EAX,EAX

    004039B4   > 8B4C94 10      MOV ECX,DWORD PTR SS:[ESP+EDX*4+0x10]  ;  读取注册码各部分的字符串

    004039B8   . 85C9           TEST ECX,ECX

    004039BA   . 74 03          JE SHORT Acid_bur.004039BF

    004039BC   . 0341 FC        ADD EAX,DWORD PTR DS:[ECX-0x4]

    004039BF   > 4A             DEC EDX

    004039C0   .^75 F2          JNZ SHORT Acid_bur.004039B4

    004039C2   . E8 69FDFFFF    CALL Acid_bur.00403730                 ;  获取name值

    004039C7   . 50             PUSH EAX                               ;  将name压入栈中

    004039C8   . 89C6           MOV ESI,EAX

    004039CA   > 8B449C 14      MOV EAX,DWORD PTR SS:[ESP+EBX*4+0x14]  ;  Acid_bur.0042FBC8

    004039CE   . 89F2           MOV EDX,ESI

    004039D0   . 85C0           TEST EAX,EAX

    004039D2   . 74 0A          JE SHORT Acid_bur.004039DE

    004039D4   . 8B48 FC        MOV ECX,DWORD PTR DS:[EAX-0x4]

    004039D7   . 01CE           ADD ESI,ECX                            ;  计算当前部分激活码的长度

    004039D9   . E8 66EDFFFF    CALL Acid_bur.00402744                 ;  将部分name值替换为激活码

    004039DE   > 4B             DEC EBX

    004039DF   .^75 E9          JNZ SHORT Acid_bur.004039CA

    004039E1   . 5A             POP EDX

    004039E2   . 58             POP EAX

    004039E3   . 85D2           TEST EDX,EDX

    004039E5   . 74 03          JE SHORT Acid_bur.004039EA

    004039E7   . FF4A F8        DEC DWORD PTR DS:[EDX-0x8]

    004039EA   > E8 D5FCFFFF    CALL Acid_bur.004036C4

    004039EF   . 5A             POP EDX

    004039F0   . 5E             POP ESI

    004039F1   . 5B             POP EBX

    004039F2   . 58             POP EAX

    004039F3   . 8D2494         LEA ESP,DWORD PTR SS:[ESP+EDX*4]

    004039F6   . FFE0           JMP EAX

    004039F8   . C3             RETN

    将断点断在函数的起始部分,单步跟踪查看

    汇编代码部分

    可以看到,程序会先计算name的长度,若长度小于4则直接弹出错误信息窗口。

    程序会取出我们输入的name的第一个字节,这里简称为name[0]

    将name[0]的值乘以0x29再乘以0x2即为部分注册码的值,例如我们输入的name为123456789,name[0]=1,这个1为字符串1,它的ASCII码值为0x31,则0x31*0x29*0x2 = 4018,通过刚刚的寄存器窗口可以看到我们的注册码为CW-4018-CRACKED,即中间数字部分的注册码已经求出

    0042FA1E  |. E8 35B0FEFF    CALL Acid_bur.0041AA58                 ;  用于计算name的长度

    0042FA23  |. 8B45 F0        MOV EAX,DWORD PTR SS:[EBP-0x10]

    0042FA26  |. 0FB640 03      MOVZX EAX,BYTE PTR DS:[EAX+0x3]

    0042FA2A  |. 6BF0 0B        IMUL ESI,EAX,0xB

    0042FA2D  |. 8D55 EC        LEA EDX,DWORD PTR SS:[EBP-0x14]

    0042FA30  |. 8B83 DC010000  MOV EAX,DWORD PTR DS:[EBX+0x1DC]

    0042FA36  |. E8 1DB0FEFF    CALL Acid_bur.0041AA58

    0042FA3B  |. 8B45 EC        MOV EAX,DWORD PTR SS:[EBP-0x14]

    0042FA3E  |. 0FB640 02      MOVZX EAX,BYTE PTR DS:[EAX+0x2]

    0042FA42  |. 6BC0 0E        IMUL EAX,EAX,0xE

    0042FA45  |. 03F0           ADD ESI,EAX

    0042FA47  |. 8935 58174300  MOV DWORD PTR DS:[0x431758],ESI

    0042FA4D  |. A1 6C174300    MOV EAX,DWORD PTR DS:[0x43176C]

    0042FA52  |. E8 D96EFDFF    CALL Acid_bur.00406930

    0042FA57  |. 83F8 04        CMP EAX,0x4                            ;  判断name长度是否大于4

    0042FA5A  |. 7D 1D          JGE SHORT Acid_bur.0042FA79

    0042FA5C  |. 6A 00          PUSH 0x0

    0042FA5E  |. B9 74FB4200    MOV ECX,Acid_bur.0042FB74              ;  ASCII 54,"ry Again!"

    0042FA63  |. BA 80FB4200    MOV EDX,Acid_bur.0042FB80              ;  ASCII 53,"orry , The serial is incorect !"

    0042FA68  |. A1 480A4300    MOV EAX,DWORD PTR DS:[0x430A48]

    0042FA6D  |. 8B00           MOV EAX,DWORD PTR DS:[EAX]

    0042FA6F  |. E8 FCA6FFFF    CALL Acid_bur.0042A170

    0042FA74  |. E9 BE000000    JMP Acid_bur.0042FB37

    0042FA79  |> 8D55 F0        LEA EDX,DWORD PTR SS:[EBP-0x10]        ;  EBP-0x10存储着name值,并赋值给EDX

    0042FA7C  |. 8B83 DC010000  MOV EAX,DWORD PTR DS:[EBX+0x1DC]

    0042FA82  |. E8 D1AFFEFF    CALL Acid_bur.0041AA58

    0042FA87  |. 8B45 F0        MOV EAX,DWORD PTR SS:[EBP-0x10]

    0042FA8A  |. 0FB600         MOVZX EAX,BYTE PTR DS:[EAX]            ;  取第一个字节到EAX中

    0042FA8D  |. F72D 50174300  IMUL DWORD PTR DS:[0x431750]           ;  乘以0x29

    0042FA93  |. A3 50174300    MOV DWORD PTR DS:[0x431750],EAX

    0042FA98  |. A1 50174300    MOV EAX,DWORD PTR DS:[0x431750]

    0042FA9D  |. 0105 50174300  ADD DWORD PTR DS:[0x431750],EAX        ;  乘以2

    0042FAA3  |. 8D45 FC        LEA EAX,DWORD PTR SS:[EBP-0x4]

    0042FAA6  |. BA ACFB4200    MOV EDX,Acid_bur.0042FBAC

    0042FAAB  |. E8 583CFDFF    CALL Acid_bur.00403708

    0042FAB0  |. 8D45 F8        LEA EAX,DWORD PTR SS:[EBP-0x8]

    0042FAB3  |. BA B8FB4200    MOV EDX,Acid_bur.0042FBB8

    0042FAB8  |. E8 4B3CFDFF    CALL Acid_bur.00403708

    0042FABD  |. FF75 FC        PUSH DWORD PTR SS:[EBP-0x4]

    0042FAC0  |. 68 C8FB4200    PUSH Acid_bur.0042FBC8                 ;  UNICODE "-",注册码用"-"字符串隔开

    0042FAC5  |. 8D55 E8        LEA EDX,DWORD PTR SS:[EBP-0x18]

    0042FAC8  |. A1 50174300    MOV EAX,DWORD PTR DS:[0x431750]

    0042FACD  |. E8 466CFDFF    CALL Acid_bur.00406718

    0042FAD2  |. FF75 E8        PUSH DWORD PTR SS:[EBP-0x18]

    0042FAD5  |. 68 C8FB4200    PUSH Acid_bur.0042FBC8                 ;  UNICODE "-",注册码用"-"字符串隔开

    通过输入不同的注册码,我们可以发现注册码的形式为CW-*****-CRACKED即只有中间部分的注册码是通过name值变换得来,而其他部分的注册码则是固定不变的,因此生成注册码的代码为,代码写的较为稀烂。

    #include<stdio.h>

    #include<stdlib.h>

    #include<string.h>

    int main()

    {

      char flag[20];

      char text[20];

      int i = 0;

      scanf("%s",flag);

      while(flag[i]!='\0')

      {

        i++;

        if(i>4)

          break;

      }

      if(i<4)

      {

        printf("长度需要大于4!\n");

        exit(-1);

      }

      i = flag[0]*0x29*2;

      printf("CW-%d-CRACKED\n",i);

      return 1;

    }

    补充

    当我们看到这些间接寻址时,可能因为代码太多已经忘记此时里面的值,可以点击数据窗口->Crtl+G输入你想看的地址,例如我输入了0x43176c则可以看到该段里面的值

    可以看到存储的值即我输入的name值012345678,这样可以随时查看段地址里存储的值,方便阅读汇编代码

    总结

    虽然程序不是十分复杂,但是可以帮助我们去熟悉OD的使用以及对汇编的应用,我也是通过该程序学到了很多,希望能够帮助到大家

    参考链接

    https://www.52pojie.cn/thread-264393-1-1.html

    相关实验:ARM漏洞利用技术五--堆溢出

    相关文章

      网友评论

        本文标题:汇编入门你应该知道的知识

        本文链接:https://www.haomeiwen.com/subject/urchfktx.html