标题: DOS版三国志英杰传的研究心得——壹, 从寄存器到函数
性别:未知-离线 漫漫苦短

Rank: 1
组别 百姓
级别 在野武将
功绩 0
帖子 16
编号 545816
注册 2023-12-25


发表于 2025-1-19 19:19 资料 短消息 只看该作者
DOS版三国志英杰传的研究心得——壹

在序这个章节中,我们做了一些事,初步接触了IPAPro,观察了两种形态main.exe,以及它们的对应关系,但似乎什么都没做,我们并不清楚IPAPro为什么要修改原始main.exe中的内容,为什么要对main.exe进行去头加尾的操作,那是因为我们只是把main.exe当成一个普通的文件而已,进入这个章节,我们将使用IPAPro对main.exe进行程序上的研究。


顶部
性别:未知-离线 漫漫苦短

Rank: 1
组别 百姓
级别 在野武将
功绩 0
帖子 16
编号 545816
注册 2023-12-25


发表于 2025-1-19 19:19 资料 短消息 只看该作者
一、寄存器

在进行程序的研究之前,我们得稍微了解一些16位程序的寄存器知识。16位程序与现在的32位64位程序不同,它的每个寄存器只有2字节(0-65535),而不是4字节或8字节。
寄存器的名字也不多,通用寄存器AX, DX, CX, BX,当然这4个寄存器也各有各的用处;
地址寄存器SI, DI,当然它们有时也在做通用寄存器的事;
然后是CS, IP,这两个寄存器是一组的,它们保存当执行的程序语句的地址,CS就是保存其中段地址的寄存器,而IP就是保存其中偏移地址的寄存器;
DS保存程序的数据段地址的寄存器,SS保存程序的栈段地址的寄存器,SP和BP都是与栈相关的偏移地址的寄存器;
ES也是一个保存段地址的寄存器,它的特殊之处在于,它好像没有归属感,CS可能会随着程序的执行变动,DS, SS一般情况下变动不大,而ES则算的上是变动很频繁,因为它是作为一个辅助(额外)的段地址的寄存器;
还有一个标志寄存器,虽然它也是只有2字节(16bit),但其中1个bit就能有一种作用,CF, PF, ZF, SF, OF, DF都是其中的1bit的标志位。
那么要看这些寄存器都在程序中起什么作用,那就得看其中的代码了。


顶部
性别:未知-离线 漫漫苦短

Rank: 1
组别 百姓
级别 在野武将
功绩 0
帖子 16
编号 545816
注册 2023-12-25


发表于 2025-1-23 19:19 资料 短消息 只看该作者
二、一条语句的函数

我们现在就从代码开始研究,而代码中包括了若干个函数,还有数据,寄存器可以说就是替代码用一条条语句来操作数据。可以转到IDAPro界面的左边,有个Functions界面,不看不知道啊,一个241KB的main.exe竟然有1200多个函数,而且它们的名字大多数名字都是sub_开头,以函数的开始地址为结尾,不过我们还是找到了几个“另类”的函数nullsub,让我们看看里面究竟藏在怎样的语句。

seg000:57CC          nullsub_1       proc far                ; CODE XREF: sub_26BB6+6C↓P
seg000:57CC CB                           retf
seg000:57CC          nullsub_1       endp

seg000:57CD          nullsub_2       proc far                ; CODE XREF: sub_26BB6+76↓P
seg000:57CD CB                           retf
seg000:57CD          nullsub_2       endp

不点开不知道,原来这些函数都只有一条retf语句,对应的汇编码是CB,但这条语句好像并没有涉及到寄存器,莫非这个CB都还有另一个很“关键”的作用?

对的,retf这条语句很“关键”。如果程序执行到了CS1:IP1,在这里要调用一个函数,于是CS和IP都可能改变,CS和IP变化称为远跳转,CS不变IP变称为短跳转或近跳转,总之可能程序跳到CS2:IP2去执行那个函数,但那个函数执行完了,需要回到原来的CS1:IP1处继续执行代码,那么它要怎么回来?不能是个单程票吧,于是retf这条语句就起这样的作用了。
不过等等但这个函数只有一条retf语句,也就是说,这个函数是个空函数,CS:IP刚刚跳到了这里,又跳回去了,并且好像我们并不知道这个函数执行前从哪里跳过来了,又要跳到了哪里。

但IDAPro也“猜到了”我们的想法,在这个函数右边有句绿色的文字 CODE XREF: sub_26BB6+6C↓P,我们双击“sub_26BB6”或单击它再按下回车,就跳到了sub_26BB6那个函数那里,然而我们却只发现了茫茫多的代码,也根本这条语句看不出来要干什么,总之我们看到了这个函数是如何被调用的,不过像sub_26BB6还是太过于复杂了,我们目前并不需要分析这样的函数。

[ 本帖最后由 漫漫苦短 于 2025-1-24 19:19 编辑 ]
顶部
性别:未知-离线 漫漫苦短

Rank: 1
组别 百姓
级别 在野武将
功绩 0
帖子 16
编号 545816
注册 2023-12-25


发表于 2025-1-24 19:19 资料 短消息 只看该作者
三、一条“没用”的语句

可能你会想这个几乎是空的函数时怎么出现或者产生的,从某种角度来说,其实程序不从CS1:IP1跳到CS2:IP2都可以一样正常运行嘛。
对的,其实的确如此,我们来看一下sub_26BB6函数中调用这个函数的代码。

seg001:9CC2 9A CC 57 00 10                 call    nullsub_1
seg001:9CCC 9A CD 57 00 10                 call    nullsub_2

接着我们找一下规律,首先这两条语句的第1个汇编码都是9A,我们之前介绍了一个两字节数据由于小端字节序的原因,nullsub函数的偏移地址是反过来存储的,也就是说第2, 3个汇编码就是放着调用函数的偏移地址,于是CC和CD的区别就可以解释了,最后第4, 5个汇编码放着的段地址,也就是seg000这个段地址(注意不是sub_26BB6函数的段地址,而是要调用的函数nullsub_1和nullsub_2的段地址,见上一节)。

有人可能知道有一个指令是nop,对应的汇编码是90,有些破解程序的方式就是将一部分汇编码修改为90,从而实现了绕过某些语句来修改程序原始内容(比如不用输入密码等等),那么我们这里能不能实现将这句代码修改为5个nop,这样就不用跳到nullsub那里去了,理论上是可行的。

[ 本帖最后由 漫漫苦短 于 2025-1-24 19:29 编辑 ]
顶部
性别:未知-离线 漫漫苦短

Rank: 1
组别 百姓
级别 在野武将
功绩 0
帖子 16
编号 545816
注册 2023-12-25


发表于 2025-1-25 19:19 资料 短消息 只看该作者
四、一些简单的函数(上)——AL寄存器和AX寄存器

继续翻看Functions界面的函数,可以看到一堆标上蓝底且有特殊命名的函数,说明IDAPro确实识别了其中的一些函数并且解释了其中的作用,但是,这些函数其实跟英杰传的作用并不大,因为这些函数算库函数,相当于是一些已经写好的并且程序可以直接调用的函数,而这些函数也算是替我们把大部分程序启动和结束的事情做了,而中间的事情由程序的作者来设计,也就是用户代码中的函数才是我们研究的重点,但由于没有原始代码对照,用户代码一般不会被IDAPro识别出具体的函数和功能。

所以我们先从简单的函数来观察,代码是怎么改变AX寄存器的值。Functions界面的右上角有个放大的按钮(鼠标移动上去是Fullscreen),或者向右拉伸Functions界面的宽度,移动下面的滚动条,就能看到Function name右边还有Segment, Start, Length, Local, Argument等区分这些函数的参数。说实话,这个Functions界面的用法就和Windows系统下的文件资源管理器差不多的用法,总之我们要注意到Length这个参数,点击一下Length,就能让Functions界面的函数从小到大排序,或者从大到小排序。我们注意那些nullsub函数大部分长度都是1,不用看就知道里面的代码都是retf,看下面几个长度不超过5的简单函数都在做什么事。

seg001:D6C6          sub_2A626       proc far                ; CODE XREF: sub_2A63A+10B↓P
seg001:D6C6                                                  ; sub_2A768+FC↓P
seg001:D6C6                                                  ; DATA XREF: ...
seg001:D6C6 B0 FF                        mov     al, 0FFh
seg001:D6C8 CB                           retf
seg001:D6C8          sub_2A626       endp

seg001:D6CA          sub_2A62A       proc far                ; CODE XREF: sub_2A63A+10B↓P
seg001:D6CA                                                  ; sub_2A768+FC↓P
seg001:D6CA                                                  ; DATA XREF: ...
seg001:D6CA B0 FF                        mov     al, 0FFh
seg001:D6CC CB                           retf
seg001:D6CC          sub_2A62A       endp

seg003:18E2          sub_3E7E2       proc far                ; CODE XREF: sub_3E990+60↓P
seg003:18E2                                                  ; DATA XREF: dseg:432C↓o
seg003:18E2 33 C0                        xor     ax, ax
seg003:18E4 CB                           retf
seg003:18E4          sub_3E7E2       endp

seg001:E114          sub_2B074       proc far                ; CODE XREF: sub_2B078+7↓P
seg001:E114                                                  ; DATA XREF: dseg:off_42B8E↓o
seg001:E114 32 C0                        xor     al, al
seg001:E116 CB                           retf
seg001:E116          sub_2B074       endp

seg003:164C          sub_3E54C       proc far                ; CODE XREF: sub_3E990+60↓P
seg003:164C                                                  ; DATA XREF: dseg:41F8↓o ...
seg003:164C B8 02 00                     mov     ax, 2
seg003:164F CB                           retf
seg003:164F          sub_3E54C       endp

我们发现了AL这个寄存器,这个寄存器和AX寄存器有什么关系?请看下一节的介绍。
顶部

正在浏览此帖的会员 - 共 1 人在线




当前时区 GMT+8, 现在时间是 2025-2-4 06:24
京ICP备2023018092号 轩辕春秋 2003-2023 www.xycq.org.cn

Powered by Discuz! 5.0.0 2001-2006 Comsenz Inc.
Processed in 0.010708 second(s), 9 queries , Gzip enabled

清除 Cookies - 联系我们 - 轩辕春秋 - Archiver - WAP