专栏首页农夫安全OD调试破解笔记

OD调试破解笔记

整个文章都是参照

使用OllyDbg从零开始Cracking

这份文档写的,不是什么干货,就是一个学二进制的笔记

破解的程序 Splish.exe

使用软件 OD

首先直接把exe文件拉进去OD

左上角,反汇编窗口,默认自动对主程序分析,并显示附加的信息

下断点,单步执行,调试,很多时候都是在这个窗口

右上角,寄存器窗口

EAX “累加器”,很多加法乘法指令的缺省寄存器

ECX ”计数器”,重复(REP)前缀指令和loop指令的内定计数器

REP 重复执行某条指令,直到ECX=0

Loop 重复执行某个指令块,直到ECX=0

EDX 总是用来存放整数除法产生的余数

EBX “基地址”,在内存寻址是存放基地址

ESP 专门用作堆栈指针,被形象的称为栈顶指针,压入堆栈的数据越多,ESP越小

EBP 基址指针,因为ESP始终指向栈顶,所以EBP主要用来在堆栈中寻址用的

针对ESP EBP 网上有找到一个例子,解释的很容易理解

******************************************************************

-------------------------------------------------------------------------------- esp是堆栈指针  ebp是基址指针 

那两条指令的意思是 将栈顶指向 ebp 的地址  ---------------------------------------------------------------

以下摘自网上一篇文章: 

pushebp;ebp入栈  movebp,esp;因为esp是堆栈指针,无法暂借使用,所以得用ebp来存取堆栈  subesp,4*5;下面的wsprintf一共使用了5个参数,每个参数占用4个字节,所以要入栈4*5个字节  push1111 push2222 push3333 pushoffsetszFormat pushoffsetszOut callwsprintf;调用wsprintf addesp,4*5;堆栈使用完毕,“还”回4*5个字节给系统  ... movesp,ebp;恢复esp的值  popebp;ebp出栈  ret

明白了吗?主要是用来保存/恢复堆栈,以便传递参数给函数。  在MASM里面,有一条更方便的语句,就是invoke 使用它后,你就不用自己做这些事情了。 

---------------------------------------------------------------

esp始终指向栈顶,ebp是在堆栈中寻址用的

我的理解:

调用一个函数时,先将堆栈原先的基址(EBP)入栈,以保存之前任务的信息。然后将栈顶指针的值赋给EBP,将之前的栈顶作为新的基址(栈底),然后再这个基址上开辟相应的空间用作被调用函数的堆栈。函数返回后,从EBP中可取出之前的ESP值,使栈顶恢复函数调用前的位置;再从恢复后的栈顶可弹出之前的EBP值,因为这个值在函数调用前一步被压入堆栈。这样,EBP和ESP就都恢复了调用前的位置,堆栈恢复函数调用前的状态。

*******************************************************************************

ESI

EDI

源/目标索引寄存器”,这个是指在串操作指令里的,如 movs/cmps/stos/lods。这这类指令里,esi 和 edi 的使用是固定的,比如 movs 是由 ds:[esi] 复制到 es:[edi] 处,无可变化(据说 ds: 是可以被段前缀指令改动的),尽管指令表面上没有任何的表示。 此外,它们又作为通用寄存器可以进行任意的常规的操作,如加减移位或普通的内存间接寻址(这时是不和 ds: 或 es: 联动的)。

可以理解为,跟EAX这类的通用寄存器一样,但是在某些指令下的使用情况是固定的,如上例

C 进位标志位

无符号运算是否产生进位或借位。运算结果的最高有效位向更高位进位或者借位,CF置1,否则置0。

P 奇偶校验位

运算结果低8位中'1'的个数。'1'的个数为偶数,PF置1,否则置0。

A 辅助进位标志位

低半字节向高半字节进位或借位。字操作时低字节向高字节进位或借位,AF置1,否则置0。

Z 全零标志位

运算结果为0,ZF置1,否则置0

S 符号标志位

运算结果为负数,SF置1,否则置0

O溢出标志位

有符号运算是否溢出。运算结果超过了8位或者16位有符号数的表示范围,OF置1,否则置0。

左下角,数据窗口

显示的是内存地址以及存放的数据

右下角,堆栈窗口

显示的是ESP指向的地址,调试的时候如果有函数调用,可以在这个窗口看到压栈和出栈的情况。

基本的介绍完了,接下来就是这个程序的破解

运行一下程序

有3个输入框,第一个验证码的比较简单,这次不讲这个。

主要是第2和第3个框。

Name是输入一个名字,serial相当于这个名字对应的序列号

其实这个得破解就是相当于我们平常用的注册机,我们随便输入一个名字,然后注册机产生一个系列号,然后验证成功。

开始

按教程的步骤,先查找API

如下如图

右键单击,查找----选择当前某块中的名称

找到GetWindowsTextA

这个我理解为是一个窗口控件,因为我们是在调用一个可输入的窗口后再输入name和系列号的,所以先在这个位置下一个断点。

然后按F9运行程序

结果发现输入名字和系列号后,程序直接运行,判断错误。没有按我们预想的停止在窗口调用的地方。

因为是新手,只能跟着教程,结果以为是OD有问题,换了好几个版本还是一样,后面突然想到,可能是我们下的断点不对,那我们换一个想法,我们查找一下参考文本字串

同样的,右键---查找---所以文本参考字串

我们看到了几个熟悉的字符串

Good job,now keygen it

Sorry,please try again

这个地方是显示我们输入的系列号是否正确的地方,那我们选中其中一个,双击跳回调试窗口

然后我们往回找,发现两个GetWindowsTextA

地址分别为4015F1 40160D

对比一下我们刚才下断点的那个地方的地址,发现是不一样的

所以,我们把这个断点删掉,把断点断在4025F1

然后按F9运行

我们按教程的一样

名字输入narvaja

系列号输入 988898

然后点击按钮

程序并没有跳出正确或者错误的判断,而是暂停在了我们下断点的地方

我们看下堆栈窗口,看到有个buffer=splish.00403242

这里开辟了一段缓冲区域来存放我们输入的系列号,选中这段,右键--数据窗口跟随。我们看一下数据窗口

里面是空的,数据都为0

点击菜单栏--调试--执行到返回

看下数据窗口,发现数据已经写进去了,看红色箭头

然后按下F7

回到刚才主界面

因为我们输入的是错误的系列号,所以我们试着在缓冲区的内存下一个断点

选中989898,右键--断点---内存访问

运行起来,我们断在了这里,如下图

我们按F7单步执行的话,会发现错误系列号的第一个字节移动到了EAX中

看一下接下来的这段代码

CDQ

IDIV ESI

CDQ指令双字扩展,把EAX中的符号位扩展到EDX中去,然后EDX:EAX对应的值除以ESI,商保存到EAX中,余数保存到EDX中。EAX符号位扩展到EDX中,EDX的值应该变为零,相当于对EDX进行XOR EDX,EDX操作。现在不需要将EDX清零了,因为CDQ指令已经帮我们完成了该操作。

所以当前情况下我们不必每次循环之前将EDX赋值为零,我们只需要在IDIV指令之前加上一个CDQ指令即可。

EDX:EAX除以ECX,商存放在EAX中,余数存放到EDX中。好了,我们现在来看看具体的实现。

第一个字节为39,除以ECX(值为0A)。

F7单步调试一下

上图为执行IDIV前

下图是执行后

商为5保存在EAX 余数为7保存在EDX

接下来是把EDX的低位即DL的值07保存到内存地址指向的内存单元

然后接下来是

Inc ebx

cmp ebx , dword ptr ds:[0x403467]

Jnz short splish.00401669

EBX的值为0,然后递增1,接着与6进行比较,如果不相等,则跳到00401669

这里的6是我们输入的989898的长度,存放在内存地址0x403467指向的内存单元

这里肯定不相等,所以跳回到开始的地方,对第二个字节进行操作

接下来就是跟前面一下,不在重复说明。我们直接单步运行到989898执行完毕

然后跳出循环如图

接下来就是判断系列号的正确和错误并给出提示

那我们先来看看,什么情况下会跳转到正确的情况

但是因为我们输入的是错误的,所以我们看下接下来是怎么执行的

看下ESI和EDI所保存的地址

然后eax,ecx进行比较,相等的话,跳转为实现,然后ebx加1,跳转到4016b6,判断一下是不是整个用户输入的989898是否比较完成,完成并且系列号都是正确的话,整跳转到正确的提醒框。

那这里面,最主要得是,eax和ecx的比较,如果两个不相等,则会直接跳转错误

Ecx保存的是esi指向的内存单元,我们通过前一步计算所求得的余数07

Eax保存的是edi所指向的内存单元的数据是02

也就是说只有ecx为02时,则就会跳转到正确的情况

上面是第一个字节的情况,那么第二个字节呢,我们直接找到EDI所指向的内存地址

所以我们可以得出

第一个字节的算式是这样的

39=5*0A+7

也就是说除法运算的结果是39/0A 商为5,余数为7。所以我们可以通过反向运算5乘以0A然后加上7得到39。

所以只要我们求得的余数为02 08 08 03 05 05

则能破解成功

所以正确的系列号应该是

5*0A+02=34(十六进制)----ascii 4

5*0A+08=40(超出30-39的范围)(因为ascii0-9对应的十六进制就是30-39)

注:因为我们输入的错误系列号为989898,对应的十六进制为39 38 39 38 39 38,而他们除以0A后的商都为5,所以求其正确系列号的时候,都是5*0A+xxxx

所以因为变换为 正确字节值 = 4*0A + 平衡值

第二个数应该为 4*0A+08=30---ascii 0

一次类推得出正确的系列号为 4005775

最后我们再梳理一遍

我们随手输入一个系列号 989898

然后 程序计算出了,长度为6,通过通过循环6次,把989898一个个字节进行除以0A,求得商和余数

最后余数和本身存在的一段数据进行比较,如果相等的话,则系列号正确,如果其中一个错误的话,则系列号错误。

本文分享自微信公众号 - 网络安全社区悦信安(yuexin_an),作者:NGLing

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-11-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 信息安全的压力到底大不大

    0x00 前言 或许我们都看到过下面这张图: ? 我们也经常看到新闻中各式各样的报道体现着国家对网络安全的重视。 但是似乎我们并不明白为什么如此? 恰好农夫的官...

    用户1467662
  • XXE漏洞挖掘分享

    XXE漏洞挖掘 基础知识 DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。DTD 可以在 XML 文档内声明,也可以外部引用。 引用外部DT...

    用户1467662
  • 大家好,给大家介绍一下,这是linux运维安全之SSH安全

    SSH一般用途 提供shell,解决telnet不安全的传输 1、修改默认ssh默认端口 vi /etc/ssh/sshd_config 修改之后重启 >sys...

    用户1467662
  • AMD、Intel、NVIDIA芯片三巨头内战

    近日,AMD Zen 3桌面端处理器正式发布,算是把Intel、AMD、NVIDIA三大通用芯片巨头近几年的激烈角逐推向了一个高潮。

    刘旷
  • 宋宝华:LEP ( Linux 易用剖析器) 是什么,为什么以及怎么办 ( 2 )

    LEP 是 Linuxer 之 LEP 项目组正在致力于打造的一个开源项目,LEP 项目组欢迎开源爱好者加入和参与。这是 LEP 文档《 LEP 是什么,为什...

    Linuxer
  • linux和windows互传文件,用户配置文件和密码配置文件,用户组和用户管理

    同样的也会弹出一个界面让你选择需要传递到Linux上的文件,文件保存的路径是你Linux当前输入此命令的路径

    端碗吹水
  • nginx(一) 基础知识

    1. location / {} 2. location /abc {} #高优先级

    alexhuiwang
  • 终于,在2019年公司把我(们)裁了

    先说说LZ吧,和公司签了3年合同,6个月试用期,临近转正(还有一周就可以转正),也没有违反公司规章制度,总体感觉还好。在某个午休的中午,我还沉浸在梦乡的时候,部...

    用户2802329
  • APT-RAT(Poison ivy ) 攻击模拟及监测口令提取

    APT:高级持续性威胁,APT 攻击主要是指针对特定组织、特定领域或个人进行的蓄谋已久的攻击。如:针对一个国家的基础设施的破坏,针对国防、航空航天、医疗、军民融...

    信安之路
  • CSS3中的columns属性的用法

    表格布局中可以将元素放进设置好的单元格里,将网页进行分列分行的布局,但是表格布局有很大的局限性,现在基本上不再使用表格布局,只是在有表格的时候使用表格来进行局部...

    无邪Z

扫码关注云+社区

领取腾讯云代金券