加密与解密 调试篇 动态调试技术 (一)-OllyDbg的使用 TraceMe的逆向

目录

OllyDbg调试器的使用

CPU窗口

 反汇编窗口

信息面板

数据面板

寄存器面板

栈面板

OllyDbg的配置

界面设置

调试设置

 加载符号文件

 基本操作

调试

单步跟踪

如果我们想直接运行

 如果想重新运行

设置断点

下面对这个程序进行完整的调试分析

方法1 猜函数

方法2 命令窗口查看

这里还有另一个确定关键函数的方式

再一次调试程序

我们看看能不能直接取得序列码


OllyDbg调试器的使用

CPU窗口

 我们进行载入的时候 主要返回的是CPU窗口 是最主要的窗口 对应面板的C

 反汇编窗口

我们先查看CPU窗口 打开后是有 5个面板

 主要查看反汇编窗口

我们可以对这些列进行操作

操作都是进行双击

地址: 显示被双击行地址的相对地址 再次双击返回标准地址模式

 这里就能出现相对于双击地址的其他地址的偏移量

十六进制机器码:设置或取消无条件断点 对应快捷键是F12

反汇编:调用汇编器 可直接修改汇编代码 快捷键是空格

注释:添加注释 快捷键是;

从键盘选择多行 按住shift +上下键 可以实现 也可以右键快捷菜单命令实现
ctrl + 上下 可以滚动汇编(对于数据和代码混合 这个方式很有用)

信息面板

在进行动态跟踪的时候 信息面板窗口 显示指令和寄存器的值 API函数的调用提示和跳转信息

数据面板

数据面板是以十六进制和字符方式显示文件在内存中的数据

 要显示制定的内存地址数据
右键快捷键的 go to expression 或者 ctrl+G 实现

寄存器面板

寄存器面板显示CPU各个寄存器的值 支持浮点、MMX、3DNow!寄存器

可以右键或者窗口标题切换显示寄存器的方式

栈面板

显示栈的内容 就是 ESP指向地址的内容 将数据存入栈叫做入栈

从栈取出数据叫做出栈

栈窗口很重要 各个API函数和子程序都是利用它传递参数

OllyDbg的配置

 在选项界面 有两个设置 一个是界面设置 一个是调试设置

界面设置

 这里存放着两个路径

UDD 是 OllyDbg的工程文件 保存着当前调试的一些状态 
断点 注释等

插件是用于扩充功能 当我们把插件复制到 plugin目录中 
相对应的选项就会在 插件中显示出来

调试设置

 加载符号文件

使用lib文件(符号库) 可以让OllyDbg 以函数名字显示DLL 中的函数

在调试中 选择导入库

 基本操作

对于windows程序 只要API被调用 我们几乎就可以得到消息

所以对于一个windows程序 

选择API函数作为切入点就很重要 只要有经验 就可以很容易

这里看雪给出了一个测试软件

 通过看雪我们可以了解程序的运行

 这个就是这个程序的流程

我们进行OllyDbg调试

调试

 因为我们设置了 winmain处

所以打开程序后会得到程序执行的第一条指令处

 这里 004013A0就是这个程序的入口(EntryPoint)

 通过快捷键F7可以执行一条指令

EIP指向当前要执行的指令 然后我们进行执行 EIP就会指向下一条指令

我们可以通过对地址右键 然后选择此处为新的EIP来让程序从此处开始

单步跟踪

F7     单步步进 遇到call指令进行跟进
F8     单步步过 遇到cal指令路过 不跟进
Ctrl+F9    直到ret指令中断
ATL+F9     如果进入系统领空 此命令可以瞬间返回到程序领空
F9        运行程序
F2        设置断点

其中 F8在调试的时候很频繁

如果F8 遇到就路过这个call

F7 F8的区别就是
遇到call loop 是否跳过或者跟进

 

遇到call 就会去call 里面

call 00401DA0就是调用 这个地址的子程序
一旦子程序运行完毕 就会返回call的下一条指令 
这里就是 004013FFh 

看栈窗口就能发现 调用call 下一条指令的地址就被压入栈内

按-号可以返回上一步地址
双击EIP可以返回当前地址
如果需要重复 F8 F7 我们可以使用CTRL+F8/F7

这个快捷键会直到用户 按esc 或者 F12 或者遇到其他断点 停止
如果我们已经进入了call 指令 想返回原本调用call的地方 我们可以使用ctrl+F9

 这里进入了系统领空

 按Ctrl+F9返回程序领空 因为这里进入了 DLL地址

领空 就是在某一时刻CPU的 cs:EIP执行某段代码的所有者

如果我们想直接运行

 如果想重新运行

 或者 Ctrl+F12

如果程序进入死循环 F12暂停程序

设置断点

断点是调试器非常重要的部分

可以让程序中断在指定的地方

F12作为快捷键 就可以设置断点

设置断点后 通过ALT+B 或者

 可以访问断点窗口

我们可以在窗口中对断点进行操作

下面对这个程序进行完整的调试分析

先按F9 让程序运行起来

方法1 猜函数

然后我们可以猜测函数

因为我们是输入文本框里面 所以肯定会调用 读取文本框的API函数

16位:GetDlgItemText  GetWindowText
32位(ANSI):GetDlgItemTextA     GetWindowTextA
32位(Unicode):GetDlgItemTextW    GetWindowTextW

我们通过ctrl+G 查找

跳转到这个程序的入口了  然后对这个进行设置断点

方法2 命令窗口查看

我们通过CTRL+N能调出所有的系统动态链接库的函数

然后我们可以通过命令 直接对这个函数进行断点  

 bp 就是断点

然后我们开始执行程序F9进行执行

会执行到让我们输入 因为我们断点在 文本框读取字符 所以我们输入了 然后check了 他就会中断

 

 发生中断 地址在 004011B6

 这里就是调用GetDlgItemTextA的函数参数

我们先解释一下这个函数的作用

UINT GetDlgItemTextA{
    HWND hDlg,                对话框
    int nIDDlgItem,           控件标识(id)
    LPTSRE lpString,          文本缓冲区指针
    int nMaxCount             字符缓冲区的长度
};

返回值 是 如果成功了就返回文本长度 如果失败就返回0

然后我们进继续 F8进入程序领空

 注意这里调用了GetWindowTextA函数

这里还有另一个确定关键函数的方式

我们去找GetWindowTextA函数

CTRL+F2结束进程并且重新加载程序

继续查找GetWindowTextA 并且打上断点

开始执行

并且进入

程序领空后我们能发现结果是一样的

并且根据之前的 call GetWindowTextA 我们能了解 是GetDlgItemTextA函数调用了 GetWindowTextA函数

这里我们就已经完全明白了 我们输入的值是被GetDlgItemTextA函数读取了

所以我们继续重新来

再一次调试程序

CTRL+F2重新来

并且在GetDlgItemTextA函数打上断点

执行到函数

我们就可以开始看这个函数的作用了

004011AA                                 .  8D4424 4C           lea     eax, dword ptr [esp+4C]
这里是调用 参数缓冲区地址
004011AE                                 .  6A 51               push    51                               ; /Count = 51 (81.)
这里是参数最大长度
004011B0
                                 .  50                  push    eax                              ; |Buffer
这里是把参数 缓冲区指针压入栈
004011B1                                 .  6A 6E               push    6E                               ; |ControlID = 6E (110.)
这里是参数 id 在文件resource.h中存在
004011B3                                 .  56                  push    esi                              ; |hWnd
这里是参数对话框句柄
004011B4                                 .  FFD7                call    edi                              ; \GetDlgItemTextA
调用函数 取得用户名   如果执行成功 就把用户名长度存入eax中
004011B6                                 .  8D8C24 9C000000     lea     ecx, dword ptr [esp+9C]
这里又是调用函数GetDlgTextA
004011BD                                 .  6A 65               push    65                               ; /Count = 65 (101.)
最大字符
004011BF                                 .  51                  push    ecx                              ; |Buffer
缓冲区指针
004011C0                                 .  68 E8030000         push    3E8                              ; |ControlID = 3E8 (1000.)
控件id
004011C5                                 .  56                  push    esi                              ; |hWnd
句柄
004011C6                                 .  8BD8                mov     ebx, eax                         ; |
把长度存入ebx中
004011C8                                 .  FFD7                call    edi                              ; \GetDlgItemTextA
调用函数 取得序列号 到这里 程序就取得了 用户名和序列号
004011CA                                 .  8A4424 4C           mov     al, byte ptr [esp+4C]
把长度存入al中
004011CE                                 .  84C0                test    al, al
判断是否为空
004011D0                                 .  74 76               je      short 00401248
为空就跳到报错
004011D2                                 .  83FB 05             cmp     ebx, 5
和5比大小 
004011D5                                 .  7C 71               jl      short 00401248
如果小于5 就继续跳到报错
004011D7                                 .  8D5424 4C           lea     edx, dword ptr [esp+4C]
把用户名地址存入edx
004011DB                                 .  53                  push    ebx
把长度压入栈内
004011DC                                 .  8D8424 A0000000     lea     eax, dword ptr [esp+A0]
把序列号存入eax
004011E3                                 .  52                  push    edx
把用户名压入栈
004011E4                                 .  50                  push    eax
把序列号压入栈
004011E5                                 .  E8 56010000         call    00401340
对序列号进行判断
004011EA                                 .  8B3D BC404000       mov     edi, dword ptr [<&USER32.GetDlgI>;  USER32.GetDlgItem

004011F0                                 .  83C4 0C             add     esp, 0C
栈平衡 符合c的调用
004011F3                                 .  85C0                test    eax, eax
对比 eax 如果eax为0 表示注册失败 如果eax=1表示成功
004011F5                                 .  74 37               je      short 0040122E

 这里是我们全部的执行过程

 当程序读取完 用户名的时候

参数已经压入栈内了

这里我们已经找到关键判断

004011F3                                 .  85C0                test    eax, eax
对比 eax 如果eax为0 表示注册失败 如果eax=1表示成功
004011F5                                 .  74 37               je      short 0040122E
不跳转代表成功 

我们需要注意

je是通过zf标志位进行判断 是否跳转 当zf为1 就进行跳转 如果为0 就不进行 跳转

因为不跳转就代表成功注册 所以我们把zf改为 0 就可以不跳转

原本应该对该标志位修改就可以绕过跳转 但是我这里无论改了还是没改都没有用

最简单直接把je命令 换位 nop 直接不执行 je即可

所以我们进行更改

双击更改

 然后保存

 这个时候

我们成功绕过了

这种方式是爆破

我们看看能不能直接取得序列码

我们首先要对算法进行分析

我们在之前明白了

004011E5                                 .  E8 56010000         call    00401340
对序列号进行判断

所以我们F7跟进查看是如何判断的

 这里是他的主要函数

 我们能发现这里面有进行对比 因为我们的序列号要和计算出来的对比

所以我们可以尝试 看看能不能在这个函数里面取得我们的序列号

 

 这里是对比函数的内部 我们进行运行

再栈窗口中

我们能发现出现了两个字符串 因为我当时调试的时候没有输入 序列号 所以字符串1为空

字符串2出现了值

我们打开软件看看 字符串2和我们之前输入的能不能注册成功

 

 发现成功

 到这里 我们就程序分析完

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于调试64位应用程序,你可以使用OllyDbg的64位版本或者其他支持64位调试的工具。以下是一些基本步骤: 1. 获取OllyDbg 64位版本:你可以在OllyDbg官方网站上下载最新的64位版本。 2. 打开目标程序:启动OllyDbg,并选择要调试的64位应用程序。你可以使用OllyDbg的文件菜单或拖放方式打开目标程序。 3. 设置断点:根据需要,在目标程序中设置断点。你可以通过右键单击代码窗口上的特定行或指令,然后选择"Toggle breakpoint"来设置断点。 4. 开始调试:点击OllyDbg的运行按钮或按下F9键开始调试目标程序。程序将在第一个断点处停止。 5. 调试过程中的操作: - 使用F8键逐过程执行代码,或者使用F7键逐语句执行代码。 - 使用F5键继续执行到下一个断点处。 - 使用F2键在代码窗口中设置或删除注释。 - 使用F4键在堆栈窗口中跳转到当前指令的位置。 - 使用Ctrl+G键跳转到指定地址。 6. 查看寄存器和内存:在调试过程中,你可以使用寄存器窗口查看和修改寄存器的值,使用内存窗口查看和修改内存的内容。 请注意,OllyDbg是一个强大的调试器,但对于64位应用程序的调试可能会有一些限制。在某些情况下,你可能需要考虑使用其他支持64位调试的工具,如x64dbg、IDA Pro等。此外,要成功地调试64位应用程序,你需要熟悉x86-64指令集和64位程序的调试技术

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值