快捷键&sao操作

  • F2:下断点
  • F3: 加载可执行程序
  • F4: 运行到光标所在位置
  • F5: 缩小还原当前窗口
  • F7:step in
  • F8:step over
  • F9:run
  • F12:持续单步时stop
  • Ctrl+F2:重新运行程序
  • Ctrl+F8:单步持续step over
  • Ctrl+F9:执行到函数返回出,用于跳出函数(搜API,用Ctrl+F9回到调用该API的地方)
  • Alt+F9:执行到用户代码处,快速跳出系统函数
  • Ctrl+G:跳到指定指令地址
  • Alt+<字母>:对应窗口
  • 在数据窗口Ctrl+G能直接输入寄存器搜索对应地址数据
  • eax存放返回值or返回值地址
  • test eax,eax:测试返回值是否为0,为零ZF为1
  • 修改后的文件保存:选择上修改的部分->右键->复制到可执行文件
  • Ctrl+N:打开应用程序导入表,在对应API下断点(可以右键->在每个参考上设断点)
  • Ctrl+/:pathcer窗口,显示更改过的地址内容
  • 在M窗口中,Ctrl+B搜索字符串
  • 回车在不执行的情况下查看call的函数,能够先看看大体逻辑以及是否修改了关键点,* 跳回当前eip所在位置
  • [ebp+8]:程序的第一个参数
  • 如果用mov eax,1造成后续代码覆盖,可以使用等价的mov al,1
  • 右键查找->所有参考字符串
  • 查找所有使用某一内存地址的位置:右键查找参考->地址常量
  • push和retn相互搭配,相当于跳转到push进栈的地址
  • Ctrl+N打开输入输出表,在特定API下断点

调试选项

  • 事件
    • 系统断点:OD用CreateProcessA加载DEBUG_ONLY_THIS_PROCESS参数执行,程序运行之后会触发一个INT13,在系统空间。
    • Entry point of main module:文件入口点
    • WinMain:程序的WinMain()函数入口点(windows平台下的main函数)
      • 程序不一定将WinMain作为入口点,可以在PE头中修改指向

image.png

Windows消息队列

  • 系统有一个消息队列,各程序也都维护各自的消息队列
  • 读取文本框内容:GetDlgItemText & GetWIndowsText

image.png

逆向实战

1、实战一

  • 32位寄存器可以容纳数据:0~FFFFFFFF
  • 栈:高地址(栈底)->低地址(栈顶)增长
  • call xxx
    • push eip
    • jmp xxx
  • call的方式
    • call+地址
    • call+寄存器
    • call dword ptr [eax]

image.png

  • call dword ptr [eax+5]

image.png

  • call dword ptr [<&API>]:执行系统API
    • OD中可以添加API名帮助文件,使用时右键选择符号名帮助

image.png

  • mov的方式
    • movs/movsb/movsw/movsb:按串、字节、字、双字为单位将esi寄存器指向的数据复制到edi寄存器指向的空间。
    • movsx:符号位扩展 byte->word word->dword
    • movzx:零扩展 byte->word word->dword
  • cmp
    • 比较时注意[xxx]的位数
    • 修改ZF OF CF
  • test
    • 对两个操作数按位与,但是不修改操作数,只影响操作数
    • test eax,eax:判断eax的值是否为0(ZF置1)
  • 条件跳转

image.png

2、实战二——去除nag窗口

  • 破解注册检测的方法
  • 在程序启动和关闭时出现
  • GetModuleHandle:获取程序句柄(返回在内存中的基址ImageBase)
  • 不弹窗的技巧
    • nop
    • jmp
    • MessageBox中的hWnd父进程句柄改成非0(找不到父进程句柄,不会创建MessageBoxA进程)
    • 利用PE结构
      • 在硬盘上的存储结构和载入内存时的存储结构是一样的(相对位置是一样的,不一定一对一,有些不需要载入内存)
      • 模块:一个PE进程需要的所有代码、数据、资源的集合
      • 文件结构(GetModuleHandle返回的地址之前是文件头,之后都是节区内容)
        • DOS Header
        • DOS stub
        • PE File Header
        • Image Optional Header
        • Section Table
        • Data Directories
        • Sections
      • 修改AddressEntryPoint

image.png
image.png
image.png

  1. - 上面entrypointRVA存放在在0x4000E8地址处

image.png

  1. - 修改0x4000E8地址处的RVA即改变了AddressEntryPoint,能够跳过前面的注册码验证过程,从指定入口点位置向下执行程序。

image.png

  1. - 选择改变的数据,右键,复制到可执行文件,到D窗口,保存文件

3、实战三(OD和windows加载器的区别)

  • OD中无法正常分析
  • 查看PE文件头信息,发现不合理之处,修改;在数据窗口选择改变的区域后保存修改文件。(NumberOfRvaAndSize

image.png
image.png
image.png
image.png
image.png

  • 也可以使用Olly Advance插件

image.png

4、实战四(恢复限制功能:pixtopianbook107.exe)

  • 程序安装后显示是未注册版本

image.png

  • 观察未注册限制

image.png

  • OD载入运行,发生异常
    • SEH(Structured Exception Handling,结构化异常处理)
      • 异常也是一种消息,系统接受后回去执行对应的回调函数(异常处理例程)
    • 忽略异常的方式
      • 调试选项->异常

image.png

  • 忽略异常后运行程序,在程序中接着Add,会弹出上面未注册限制的提示,这时在OD中按下暂停键,发现到dll领空,Alt+F9回到此时程序执行的位置,定位到了未注册限制的判别区域。(上述方法暂停到了CallWindowProc,不太成功)

image.png
image.png

  • 也可以右键查找所有模块名称,在MessageBox函数处下断点,执行Add后返回到弹窗位置

image.png
image.png

  • 继续向下执行到retn,然后向上找条件跳转,改成jmp,破解注册验证。右键->编辑->复制所有修改到可执行文件

image.png
image.png image.png

  • 如果想修改字符串,M窗口Ctrl+B查找到该字符串在data中的位置,修改(注意:找到的字符串位置应该在程序内存区域内)

image.png
image.png

  • 在数据区保存修改

image.png

5、实战五(使用次数限制破解:VisualSite Designer.exe)

  • 打开发现该软件有使用次数限制,关闭后会弹出广告

image.png
image.png

  • 可变跳转:例jmp eax,eax可以控制跳转地址(除了条件跳转)
  • OD中的两种断点

    • 软件断点
      • 内存断点(不推荐):每次只能设置一个,会改变整块内存的属性
      • F2:插入int 3指令,控制权回到OD
        • 只能在OD的CPU界面下使用,无法在数据段或一条指令中间下断
        • 下在dll文件中不会被保存,重启程序后断点丢失
    • 硬件断点
      • 利用调试寄存器Dr0~Dr7
        • Dr0~Dr3:存放中断地址
        • Dr4、Dr5:保留不使用
        • Dr6、Dr7:记录Dr0~Dr3的属性(r/w/x,byte/word/dword…)
  • 开始破解程序,MFC程序,封装较多。ctrl+F8定位到程序退出前关键函数,执行该函数后软件弹出次数提醒洁面。

image.png

  • 步入该函数查看实现细节,继续F7进入

image.png
image.png
image.png

  • 一直跟到dll中调用窗口的函数,在这里不能用软件断点,应该用硬件断点下断,防止重新加载时断点丢失 。重新加载,断在对应地址,步入,删除硬件断点。

image.png
image.png

  • 发现回到程序领空,继续ctrl+F8,直到断下,在断下处下断点重新加载。断下后不需要再跟进(进入后弹窗程序失控不会断下,里面是一个窗口消息循环)

image.png

  • 0x489912处的函数功能可以猜测为让使用计数器减1,让返回值eax=1,使程序正常打开。可以用mov eax,1替换。保存到可执行文件,突破了nag(次数)限制。

image.png

  • 下面消除关闭后的广告页面。
  • 重新载入,弹出广告窗口后按下暂停,打开K窗口(通过堆栈判断哪些函数被调用过了)。找到唯一在程序领空的函数调用(0x480c24),定位后下断点,重新运行断下。

image.png
image.png

  • F8后广告弹出,说明只需要把0x480C24处nop掉即可删除广告弹窗。保存到文件。
  • 分析消除nag窗口前后不同的执行逻辑(让可使用次数减为0重新分析)
    • 在nag弹窗之前F8执行,所有的跳转注释是否跳转成功,如果进入了dll,Alt+F9回到程序领空继续执行。

image.png

  • 标注好后重新跟踪,在弹窗之前应该有跳转逻辑和原来(次数>0)不同,修改该逻辑即可

image.png

6、实战六(pcsurgeon.exe)

  • 打开程序,显示是未注册,只有5天有效期

image.png
image.png
image.png

  • 破解关键点首先围绕nag窗口定位,载入后右键查找所有字符串。定位后双击。

image.png
image.pngimage.png

  • 调用该字符串的上面找到关键条件跳转。下断点。

image.png

  • 重新载入运行,断在jnz处,修改zf,nag被消除,窗口上字符串也不再显示了。

image.png

  • 方法二:不改跳转方向,改比较数据,使其注册成功(好处是不需要在多个点都打上补丁)
  • 在条件跳转之前观察比较的数据,发现一个常用地址。

image.png
image.png
image.png

  • 找到初始化改地址值的位置(决定是否注册),在所有指令设断点,重新载入,找到初始化的位置,修改对应的值,看是否能注册成功。

image.png
image.png
image.png

7、实战七(MrBills.exe)

  • 运行程序,是未注册版本

image.png
image.png
image.png

  • 开始跟踪,还是从字符串下手

image.png
image.png
image.png

  • 向上找到影响zf标志位的位置,如果注册成功,这里al不应该为0,即上面call的返回值为非零

image.png

  • 重载程序,进入该call函数跟踪。先观察程序的整体思路(注意寄存器),注意哪些call的返回值还会影响跳转,那么这些call也是需要跟进分析的。

image.png

  • 重载程序,分析深一步的call(技巧点)

image.png

  • 重载程序,分析深一步的call(call 0x406F4B)

image.png
image.png

  • retn->retn,跟进call 40701D,发现了和上面(0x406F4B)相似的逻辑

image.png
image.png
image.png

  • 修改0x406F4B处的关键点(为了改变al,将mov al,bl改为如下),修改成功

image.png
image.png

8、实战八(VB:PC2AM2_PRO.exe)

  • 分析前用PEiD查看程序的编写语言和基本信息、编译器等

image.png

  • VB程序:BASIC语言发展而来的可视化编程语言,由事件驱动的编程语言。所有的VB程序都依赖一个外部的动态链接库:MSVBVM60.dll,导致在跟踪时总是跳到dll领空。这些API能作为中介让程序和指定设备进行沟通。
    • VB破解的关键API函数(匹配)

image.png

  • 本次程序通过识别硬盘编号来唯一确定一台机器(key)

image.png

  • OD载入安装后的程序exe,Ctrl+N打开输入输出表,在特定API下断点

image.png

  • 运行,断下。F8走,找到key进行验证的地方,发现key,成功注册。

image.png
image.png

9、实战九(Flash Jigsaw Producer.exe)

  • 安装完成后打开

image.png
image.png
image.png

  • PEID查看基本信息

image.png

  • 载入OD跟踪,通过关键字符串定位(右键->查找->查找所有参考文本字串)

image.png

  • 拉到头搜索

image.png

  • 双击来到代码处,je跳转位置决定显示的是注册版本还是未注册版本,改变跳转仅能更改显示的样式。其他功能还是有限制。

image.png

  • 继续分析,搜索上述文本,断下。在je上面是测试al是否为0,al的值由栈里的一个值决定,因此要继续看栈里的值是哪里决定的。OD中显示调用来自0x4047D3

image.pngimage.png

  • 在0x4047D3处下断点,重新执行断下,验证码校检肯定在0x4047D3之前,继续从这里往前看。这里push eax就是将eax的值放入0x12E024中,即上一步的ss:[esp+0x4]。

image.png

  • eax中保存的是上一个call的返回值,因此验证步骤应该在0x404640函数中,下断点步入查看(回车查看)。
  • 首先是计算了现有reg key的长度,和4进行比较,如果长度小于4,eax置0后返回,显示未注册。因此reg key长度应该是大于等于4.

image.png
image.png

  • 继续向下,jnz跳转不应实现,0x41FF0E0应该返回值为0(这里修改eax的值可破解)

image.png

  • 修改ZF使jnz不跳转,继续向下分析

image.png

  • 不让jl跳转(修改sf),继续向下执行

image.png

10、实战十(Tekscheduler.exe)

  • Delphi逆向
  • 运行程序,出现nag,显示未注册,有添加数量的限制

image.png
image.png
image.png

  • PEiD查看程序基本信息

image.png

  • OD载入,右键搜索字符串定位

image.png

  • 代码疑惑

image.png

  • 查看哪里还能调用到mov一句(右键->查找参考->选定指令

image.png
image.png

  • 发现delphi特色!!(这里push和retn相互搭配,相当于跳转到push进栈的地址中)

    image.png

  • 其他delphi特色:call很多【原因:delphi也是面向事件(组件)的编程语言,和VB的区别是:VB跳转到动态链接库,delphi跳转到自己写的代码】

image.png

  • 找到注册过程(向上有字符串提示,在输入key之后下断点断下)

image.png
image.png
image.png

  • 单步执行分析,到一个call后跑飞到ntdll内存空间(ntdll:内核接口),看是在哪里跑飞的(减号键回到对应程序领空,加号再回到当前命令执行的地方

image.png

  • 尝试把这个call进行nop

image.png

  • 重新运行后就能继续向下走,向上的跳转忽略(八成是循环),看到有条件跳转,分析是否应该跳(看怎样能到达最后验证通过的位置),例:把下面jz改成jmp(应该无条件跳转)

image.png

11、实战十一(Xoftspy.exe)

  • 探测恶意软件的工具(系统监控):Xoftspy

image.png

  • PEiD查看基本信息
  • 这里采用API进行初始定位,获取窗体的标题、文字或控件内容使用API:GetWindowText
  • 方法一:右键->查找->所有模块间的调用,查找到GetWindowTextA,右键->在每个调用到xxx上设置断点

image.png
image.png

  • 方法二:在CPU窗口执行Ctrl+N,搜索GetWindowTextA,右键->在每个参考上设置断点

image.png

  • 下了断点之后运行程序,输入key看是否断下(前面也有断在GetWindowTextA的情况,但不是分析所需要的,那么就把相应的断点取消即可),输入key后断下的位置如图(如果都没有断下就要考虑其他函数了)

image.png

  • 单步向下,找到关键条件跳转(遇到retn返回即可,无脑F8,注意关键字符串),需要上面得到的al的值非0才能跳转(注册成功),因此上一个call很可能是验证key的关键,下断点跟进。(下面发现有一段重复代码,猜测是对输入key重复验证【防破解】)

image.png
image.png

  • F7跟进关键call,先大体浏览一下代码,发现最后retn处有对al清零,所以不应该来到这个位置,应该在上面一个retn处就返回。

image.png
image.png

  • 单步执行,注意跳转(忽略向上跳转),把跳转到错误retn的ZF都修改掉,最后能弹出注册成功的框,但是工具仍显示未注册。
  • 继续分析,重新运行定位关键字符串,看还在哪里有验证

image.png
image.png

  • 运行程序,发现按下about就触发了这个断点,跟进关键call(注意对al的修改),注意关键跳转(可以最后直接mov al,1)。运行后成功注册。

image.png
image.png
image.png

12、实战十二(DVDMenuStudio.exe)

  • inline patch:内嵌补丁,常用在加壳软件破解
  • 打开软件,30天有效期

image.png image.png

  • PEiD查看基本信息,VC++编写

image.png

  • OD载入,ctrl+N查看导入表中的所有API名称,查找函数KillTimer,右键->在每个参考上设置断点

image.png
image.png

  • 按下ok,成功断下(SetTimer和KillTimer搭配,switch的效果),如果eax不等于3就输出成功。

image.png
image.png

  • 继续向下分析,有好几个连着的KillTimer,将eax又分别与几个数比较(switch里的case,KillTimer起到case的作用),分析发现eax应该要等于4.

image.png

  • 在程序开头断下(switch所在函数)F8跟进,观察eax的变化

image.png

  • 这里考虑将eax的值赋值为4,但是实践中能够发现:mov eax,4占5个字节,大于原来的3个字节,后续机器码会被覆盖,造成堆栈的不平衡,因此要用到inline patch的方式修补。

image.png

  • 利用代码段内无用的区域(填充零为了对齐用的)进行修改

image.png
image.png
image.png

  • 右键->编辑->复制所有修改到可执行文件,重新载入修改后程序,发现程序陷入弹窗死循环。

image.png

  • 再次单步分析switch,发现eax等于B会结束循环。把patch处的4换成B重新保存,破解成功(字符串查找的陷阱!!

image.png

13、实战十二补充(DVDMenuStudio.exe)

  • 运行程序,能发现是先生成主程序,再运行nag窗口
  • 在OD中运行后点击暂停,查看堆栈窗口【K】(比用字符串更高级的定位方式),里面包含目前为止所有的操作,猜测最后几个函数是去生成nag窗口(因为一生成nag窗口我们就暂停了,还没有执行其他操作)。

image.png

  • 从最后一个分析,双击调用来自进入调用该函数的地址,下断点重新运行,主窗口出现,执行call,nag窗口出现。可见005ABE4D处是nag窗口生成的代码。

image.png

  • 从004DC0D1向上,找到这个函数的起始位置,下断点(好习惯:每次在函数内部断下都应该在函数起始下断点,方便分析整个函数),重新运行断下,单步跟踪下这个函数

image.png

  • 注意函数里的条件跳转,目标是不要到达生成nag窗口的那个call(一般越早的条件跳转越关键)

14、实战十三(ReverseMe. NAGs.exe)

  • inline patch 跟进+硬件断点
  • 打开程序

image.pngimage.png
image.png

  • PEiD查看编辑器信息

image.png

  • OD运行程序,出现nag窗口后,点击暂停断下,查看堆栈窗口【K】,发现MFC使用了调用对话框的类,点击查看对应位置(调用来自)

image.png
image.png

  • 下断点重新载入程序,执行对应call果然出现了第一个nag窗口;继续执行仍然又断在这个断点处,主窗口出现(最后一个nag同理),所以不能简单把call给nop掉。
  • 向上浏览发现有一个控制执行这个call的je跳转,因此考虑实现第1、3次je要跳,第2次(主窗口)不跳。

image.png

  • 使用inline patch,因为一般代码段都是不可写的,所以考虑把patch中用到的变量写在数据段。
  • 查看memory【M】窗口,双击.data段能查看到dump出的数据,向下找到一个空的(都是零)区域

image.png
image.png
image.png

  • 测试选定的位置(445E80)在程序运行中会不会改变【防止干扰】。下一个硬件断点,重新运行程序,看是否会断下,没有断下说明位置可用。

image.png

  • 开始制作inline patch(在00420379的je处),向下找到代码段中都是0的地方

image.png

  • 由于je处未修改前是短跳转,只占用2个字节,而patch的位置应该用长跳转(5个字节),修改后一定会覆盖目前je后的代码,所以把后面要覆盖的代码也写到patch里。
  • 利用OD的Nonowrite插件修改代码(用来写补丁代码

image.png
image.png
image.png

  • 把je改成jmp 437D6E,跳转到patch执行

image.png

  • 右键->保存到可执行文件->所有修改,保存修改后文件,载入测试,完成。

15、实战十四(URLegal.exe)

  • 对话框基本常识
    • model对话框:不允许弹框时用户在不同窗口间切换
      • 由windows为它内建一个消息循环
      • 由调用DialogBoxParam实现
    • modeless对话框:允许切换
      • 通过用户程序中的消息循环派送,可以和程序的其他消息并存
      • 由调用CreateDialogParam实现
  • 运行程序

image.png
image.png

  • PEiD检查

image.png

  • OD载入,运行程序时点击关闭会弹出一个model对话框

image.png

  • 使用eXeScope工具(exe解析工具,常用来汉化)观察程序,能看到程序中用到的很多组件

image.png
image.png

  • 找到上面的model对话框,103(十进制)是这个对话框的模版名称(hwnd Instance),在OD里查找这个句柄定位(103->0x67)。如何查找:直接查找命令push 0x67(调用DialogBoxParam肯定让这个参数入栈了)。(tips!!)

image.png

  • 定位到函数调用后,发现所在函数并没有条件跳转,说明还要向上回溯

image.png

  • 从上面函数的开头设断点,重新运行断下,查看堆栈中调用该函数的位置。在调用函数中找到关键call,要使eax不为0就注册成功。

image.png
image.png

  • 在关键call下断点,程序重新执行,刚一执行就断在该位置,说明这里就是一开始判断是否注册的点。

16、实战十五(movgear.exe)

  • 打开程序,点击关闭时弹出尾部nag窗口

image.png

  • 使用Resource Hacker查看PE信息(类似eXescope),定位到了尾部的nag,发现其template name是100(十进制)

image.png

  • OD载入程序,查找->所有命令->push 0x64(100),发现不止一个,右键在每个命令上设置断点,逐一排除。

image.png

  • 重新运行,排除的断点情况:对话窗出现的时机(出现之前的肯定都不是),找到关键跳转和它上面的关键call

image.png

  • 在call和jz下断点重新执行断下,F7进入关键call分析,有很多重点API
    • RegOpenKey:打开注册表键值(HKEY_CLASSES_ROOT or HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE or HKEY_USERS)
    • RegQueryValue:从key里找到一个键名对应的值,存放到数据缓存区
  • 最后修改eax(mov al,0x1:避免覆盖后续代码),成功爆破

17、实战十六(KeygenMe.exe)

  • keygen:注册机,有自己的算法,可能会结合计算机指纹,和用户输入进行匹配
  • 运行程序

image.png

  • OD载入,发现程序使用GetDlgItemTextA(常用拦截字符串)获取输入框中的值(字符串),在GetDlgItemTextA处下断点,运行程序按下check,断在dll里,按下Alt+F9运行结束回到用户空间。重复两次,把输入的name和key都获取到了,每次eax保存了获取的长度(函数返回值)。

image.png
image.png
image.png

  • 继续向下分析,ecx可能用来引用输入的name(字符串:字符数组)

image.png
image.png
image.png

  • 知道注册机将运算后的结果放在esi中,打一个inline patch,修改MessageBox的参数,将我们在数据段中暂存的正确的key输出。

image.png
image.png
image.png image.png

  • 研究注册机的算法

image.png

18、实战十七(ReverseMe Tutorial.exe)

  • 多态病毒:触发时解密模块进行解密,感染时加密模块进行加密并感染,加密模块每一次感染中都会修改。
    • 查杀方案:蜜罐虚拟机
  • 变形病毒:每一次感染将自身完全改写(Simile)
  • 运行程序

image.png image.png

  • 搜索关键字符串定位,下断点,发现在断点断下之前nag窗口就出现了(关键字符串失效)

image.png

  • 浏览代码 (如果分析不正常,右键->分析->删除分析),单步跟踪,发现自修改(解密过程)

image.png
image.png
image.png
image.png
image.png

  • 又跳回,接着自身解密,得到弹出框上的文本

image.png
image.png

  • 接着执行下一个call,又把数据进行了加密

image.png

  • 如何打补丁(去掉nag窗口)
  • 方法一:修改MessageBox参数,使父进程句柄无效(找到修改40101D未知的代码,使其修改后为0x1)

image.png
image.png

  • 因为401035处的代码由第一个关键call使用xor 0x5A解码而来,因此401035处应该保证num or 0x5A = 0x1. 这里num应该是0x5B,才能保证最终的push 0x0更改为push 0x1.。在内存中的位置修改。

image.png

  • 方法二:跳过MessageBox不执行,需要在第二个关键call解码后让401011处的机器码为EB57。因此逻辑是num xor 0x5A(第一次解码)= EB 57,num = B1 0D

image.png
image.png
image.png

19、实战十八

  • 反调试方法

方法一:IsDebuggerPresent(ReverseMe.A.exe)

  • 打开文件,在OD中运行和直接运行得到的消息不同。

image.png image.png

  • 单步执行,跑飞之后按减号键回到程序领空,定位关键的反调试用的call

image.png

image.png

方法二:(ReverseMe.B.exe)

  • 在OD中程序运行终止

image.png

  • 单步调试,因为用esp覆盖了不可写的区域,报错

image.png
image.png

方法三:(ReverseMe.C.exe)

image.png

方法四:(ReverseMe.D .exe)

image.png
image.png

20、实战十九(Debugger Detected.exe)

  • 有OD进程的时候运行程序

image.png

  • 单步分析

image.png

  • 在过程函数下断点,单步执行直到弹出错误信息,定位关键call,进入分析

image.png
image.png
image.png
image.png