吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 13423|回复: 24
收起左侧

[原创] 逆向笔记-逆向XX.exe

  [复制链接]
lipss 发表于 2017-4-15 08:13
本帖最后由 zjh16529 于 2019-6-6 18:28 编辑

##  名词注释

System breakpoint:系统断点,OllyDbg用CreateProcessA加载DEBUG_ONLY_THIS_PROCESS参数执行,程序运行之后会触发一个INT13,在系统空间里。


Entry point of main module:主模块的入口点,即文件的入口点。


WinMain:程序的WinMain()函数入口点


OD的设置中-选项-事件中设置

11111.png


## OD快捷键熟悉


1、F2 下断点,

2、Alt+b 打开断点编辑器,可编辑所有下过的断点

3、空格键 可快速切换断点状态。

4、Ctrl+F9.当位于某个CALL中,这时想返回到调用这个CALL的地方时,可以按“Ctrl+F9”快捷键执行返回功能。这样OD就会停在遇到的第一个返回命令(如RET、RETF或IRET)。

5、Alt+F9 如果跟进系统DLL提供的API函数中,此时想返回到应用程序领空里,可以按快捷键“Alt+F9”执行返回到用户代码命令。

6、Ctrl+G 跳转到API、地址的位置



## 逆向之猜


逆向与开发的知识是成正比关系,只有对开发特别熟悉,逆向一个程序才能猜测到该用哪个关键的API才能快速定位到程序的数据处理。


通过PEID查看程序特征,根据程序语言用IDE生成特征或者熟悉开发的API函数。就可以更方便地让我们定位到获取edit值的函数。

11111.png




GetDlgItemText 函数 用于获取对话框中指定控件的标题或文本。


‘使用OD的快捷键【Ctrl+G】跳转到API的位置下断点。


F2设置断点,当【GetDlgItemTextA】这个函数被调用OD就会中断


【ALT+B】快捷键可以打开断点窗口查看,在断点位置按【空格键】可以激活与禁用断点。

11111.png

11111.png


按快捷键【Ctrl+F9】可以回到调用函数的尾部ret处。


## 算法逆向

F7跟进004011E5地址内的函数,进入子程序call 00401340,特别值得注意的是00401359是跳转到4013680的,相关汇编代码注释如下:

11111.png


加密函数汇编注释如下:

```

00401340  push ebp                                 ;  ebp入栈

00401341  mov ebp,dword ptr ss:[esp+0xC]           ;  将用户名移动到ebp中

00401345  push esi                                 ;  esi入栈

00401346  push edi                                 ;  edi入栈

00401347  mov edi,dword ptr ss:[esp+0x18]          ;  将参数从堆栈中传给edi(用户名长度值) edi = 5

0040134B  mov ecx,0x3                              ;  ecx = 3

00401350  xor esi,esi                              ;  esi 清 0

00401352  xor eax,eax                              ;  eax 清0

00401354  cmp edi,ecx

00401356  jle XTraceMe.00401379                    ;  edi<ecx条件成立时跳转,i<len

00401358  push ebx

00401359  /cmp eax,0x7                             ;  比较eax与7的值

0040135C  jle XTraceMe.00401360                    ;  当等于7,ZF=1短跳转

0040135E  |xor eax,eax

00401360  |xor edx,edx                             ;  edx清0

00401362  |xor ebx,ebx

00401364  |mov dl,byte ptr ds:[ecx+ebp]            ;  地址低8位的一个字节,dl是存储一个字节的寄存器,ecx = 3,  [ecx+ebp] = d

00401367  |mov bl,byte ptr ds:[eax+0x405030]       ;  00405030  0C 0A 13 09 0C 0B 0A 08

0040136D  |imul edx,ebx                            ;  edx * ebx 赋值给 edx, dl为高8位,存储1字节数

00401370  |add esi,edx                             ;  edx+esi,把值赋予给esi ,esi = 4B0 + 3F2

00401372  |inc ecx                                 ;  递增指令,ecx 由 3 -> 4 -> 5

00401373  |inc eax                                 ;  eax = 1,eax++

00401374  |cmp ecx,edi

00401376  \jl XTraceMe.00401359                    ;  ecx 是否大于等于5(用户名长度), jl指令大于不等于满足时跳转

00401378  pop ebx

00401379  push esi                                 ; /<%ld>

0040137A  push TraceMe.00405078                    ; |Format = "%ld"

0040137F  push ebp                                 ; |s

00401380  call dword ptr ds:[<&USER32.wsprintfA>]  ; \wsprintfA

00401386  mov eax,dword ptr ss:[esp+0x1C]

0040138A  add esp,0xC

0040138D  push ebp                                 ; /String2

0040138E  push eax                                 ; |String1

0040138F  call dword ptr ds:[<&KERNEL32.lstrcmpA>] ; \lstrcmpA

```


程序原先输入的用户名:abcde、序列号:123456。在堆栈窗口看到的是d、e,也就是

```

   name[3]=‘d’,

   name[4]=‘e’

```


根据00401367 地址处判断,密码数组索引第3位之后的值逐位取出与固定地址的值比对。然后在0040137A  会输出密钥的值2201。


仔细逆推一遍:


```

   edx =  64 * 0C = 4B0


   edx =  65 * 0A = 3F2


   4B0 + 3F2  =  8A2


8A2对应的十进制为2210

```

逆向结论:


abcde转换为十六进制从索引值第3位开始逐位取值,64:d、65:e ,然后与00405030  0C 0A 13 09 0C 0B 0A 08对应的值进行相乘然后累加。得出的8A2转换成十进制2210就是密码的值。



把加密函数取出来就成了算号注册机,下面是加密函数反汇编转换来的C代码:


```

#include "stdafx.h"

#include <string.h>




//char name[65] = "abcdexxxx";

char name[65];

char table[8] = { 0xC ,0xA ,0x13 ,0x09 ,0x0C ,0x0B ,0x0A ,0x08 };

int main()

{

        printf(" 输入key:\n ");

        scanf_s("%s",name,65);



        //会用到一个固定地址的值

        //会用到姓名里的后两位

        //eax = i

        int user_len = strlen(name);

        int key_code= 0; //esi




        int count_ecx = 3;  //esi

        int eax = 0;      //eax

    for (; count_ecx<user_len;)

        {

                if (eax>7)

                        eax = 0;


                int ebx = 0;

                int edx = 0;


                edx = name[count_ecx];

                ebx = table[eax];

                ebx = edx * ebx;


                key_code += ebx;

                count_ecx++;

                eax++;


        }

        printf("key_code: %d", key_code);

    return 0;

}


```

11111.png


## 暴力破解


在定位到GetDlgItemText这个API处,F8单步步过向下跟随到有test判断的地方,注意观察数据堆栈区的位置。

11111.png


汇编指令注释如下:

```

0040119C  mov esi,dword ptr ss:[esp+0x100]         ;  Case 3F5 of switch 0040115E

004011A3  mov edi,dword ptr ds:[<&USER32.GetDlgIte>;  user32.GetDlgItemTextA

004011A9  push ebx

004011AA  lea eax,dword ptr ss:[esp+0x4C]

004011AE  push 0x51                                ; /Count = 51 (81.)

004011B0  push eax                                 ; |Buffer

004011B1  push 0x6E                                ; |ControlID = 6E (110.)

004011B3  push esi                                 ; |hWnd

004011B4  call edi                                 ; \GetDlgItemTextA

004011B6  lea ecx,dword ptr ss:[esp+0x9C]

004011BD  push 0x65                                ; /最大字符数

004011BF  push ecx                                 ; |文本缓冲区指针

004011C0  push 0x3E8                               ; |控件标识

004011C5  push esi                                 ; |对话框句柄

004011C6  mov ebx,eax                              ; |将用户名的长度转到ebx中

004011C8  call edi                                 ; \GetDlgItemTextA

004011CA  mov al,byte ptr ss:[esp+0x4C]            ;  将用户名的第一个字节给al

004011CE  test al,al                               ;  检查有没有输入用户名

004011D0  je XTraceMe.00401248                     ;  如果没有输入用户名跳走,告知输入的字符太少,zf=0跳转

004011D2  cmp ebx,0x5

004011D5  jl XTraceMe.00401248                     ;  如果用户名不大于5那么就跳转到错误提示处

004011D7  lea edx,dword ptr ss:[esp+0x4C]          ;  用户名地址放到edx中

004011DB  push ebx                                 ;  用户名长度

004011DC  lea eax,dword ptr ss:[esp+0xA0]          ;  密码地址放到eax

004011E3  push edx                                 ;  用户名地址入栈

004011E4  push eax                                 ;  密码地址入栈

004011E5  call TraceMe.00401340                    ;  调用函数,相当于a("123456",abcde,5)

004011EA  mov edi,dword ptr ds:[<&USER32.GetDlgIte>;  user32.GetDlgItem

004011F0  add esp,0xC                              ;  平衡堆栈

004011F3  test eax,eax                             ;  函数返回值都是在eax里面的,eax=0注册失败,eax=1注册成功

004011F5  nop                                      ;  zf标志位为0,满足条件时跳转

```


第一个test指令首先对比用户名是否大于5,不大于5就跳转到弹出错误提示的地方。否则继续执行。F8单步步过进入【GetDlgItemTextA】后面的调用查看相关的代码。004011E5地址处call调用一个函数,并且在之前push了三个参数。

11111.png


第二处test指令下面那条je跳转指令用nop填充掉。


11111.png



然后右键【复制到可执行文件】-【所有修改】


11111.png


选择全部复制

11111.png


选择【保存文件】,暴力破解就完成了

11111.png


成功截图

11111.png





## 样本引用

《加密与解密》这本书里的附带小程序TraceMe.exe。

TraceMe.zip (20.5 KB, 下载次数: 131)








免费评分

参与人数 12吾爱币 +19 热心值 +12 收起 理由
peter_king + 1 谢谢@Thanks!
Hmily + 8 + 1 用心讨论,共获提升!
liphily + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
sxisir + 1 + 1 用心讨论,共获提升!
hejialong + 2 + 1 谢谢@Thanks!
YYL7535 + 1 + 1 谢谢@Thanks!
zz0147 + 1 + 1 我很赞同!
Binarian + 1 + 1 谢谢@Thanks!
鱼无论次 + 1 + 1 谢谢@Thanks!
皇甫小杰 + 1 + 1 我很赞同!
95535916 + 1 + 1 谢谢@Thanks!
因素 + 1 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Jhin 发表于 2017-4-17 15:34
嘿嘿嘿 楼主太厚道 以后会好累的, 现在破个异地登陆的验证都要追回去3次sslv3的计算,以后不造还会累成什么样。 不过说真的, 这程序和fiddler 里面的我用的他们的正版插件真的好像,最后说出来 我的是 success
因素 发表于 2017-4-15 08:37
等待记忆中 发表于 2017-4-15 09:32
hcq2ld 发表于 2017-4-15 10:27
虽然看不懂,但要给楼主赞。
皇甫小杰 发表于 2017-4-15 10:30
我也是不懂,还是给楼主点赞
头像被屏蔽
Kay0905 发表于 2017-4-15 10:47
提示: 作者被禁止或删除 内容自动屏蔽
Three_fish 发表于 2017-4-15 11:04
虽然看不懂,但要给楼主赞。
xcz123m 发表于 2017-4-15 14:42
谢谢分享,又学到了。。
纳兰无羁 发表于 2017-4-15 17:16
强大  学习学习   感谢楼主
邪梦 发表于 2017-4-15 17:20
学习了,感谢楼主分享,
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-16 19:44

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表