逆向工程

汇编是逆向工程的基础

1、

BIT()——电脑数据量的最小单元,可以是10

   BYTE(字节)——8个位,最大值是255

   WORD()——2个字节,16个位,最大值0FFFFh

   DOUBLE WORD(双字DWORD)——2个字,4个字节,32个位,最大值0FFFFFFFF;

   KILOBYTE(千字)——32*32=1024个字节;

   MEGABYTE(兆字)——1024*1024=1048576个字节。

2

   寄存器大小一般是32位,如EAX,4个字节,储存值位0-FFFFFFFF(无符号)的数据。

但有一些寄存器是168位的,它们是不能直接寻址的。

   单字节寄存器:8位:ALAH;BLBH;CLCH;DLDH

   单字寄存器:16位:一个单字寄存器包含两个单字节寄存器。如AX=AH+AL;可以看作AXALAH组成,AHAL改变,AX也会改变。

   通用寄存器:AX(累加器):数学运算;

               BX(基址寄存器):连接栈;栈是一个存放即将会被用到的数据的地方;       CX(计数器):计数;

               DX(数据寄存器):存放数据;

               DI(目的变址寄存器):拷贝到DI;

               SI(源变址寄存器):从SI拷贝。

   索引寄存器(指针寄存器):BP(基址指针寄存器):栈区域的基地址;                        SP(栈指针寄存器):栈区域的栈顶地址。段寄存器:CS(代码段寄存器):存放应用程序代码所在段的段基址;DS(数据段寄存器);ES(附加段寄存器);SS(栈段寄存器)。

   指令指针寄存器:IP:指向下一个指令。

   双字寄存器:32位,4字节,2字;如EAX,EBX,ECX,EDX,EDI···

如果16位寄存器前面加了“E”,就代表是32位寄存器。

 3

标志寄存器:代表某种状态,标志寄存器是一个标志,只能是01,它们决定了是否要执行某个指令。ZF(零标志)OF(溢出标志),CF(进位标志)。

                                 “只要溢出,OFCF都会被设置成1?那这两个又有什么区别呢?”

      4

         段偏移:每个段都有一个偏移量,段(看作书的某一页)、偏移量(看作页的某一行)合在一起就是内存中一个具体的地址。

     5

       栈:最后放的最先被拿出来。push命令就是向栈中压入数据,pop’命令就是从栈中取出最后放入的数据并且把它存进具体的寄存器中。

     6

        指令,所有的值通常是以16进制形式储存的,大部分指令有两个操作符(如:add EAX, EBX),有些是一个操作符(如:not EAX),还有些是三个操作符(如:IMUL EAX、EDX、64);如果使用DWORD PTR [XXX]”就表示使用了内存中偏移量为[XXX]的的数据。字节在内存中储存方式是倒过来的。

        ADD(加)ADD 被加数, 加数如:add eax,123 = eax=eax+123;

         AND(逻辑与)AND 目标数, 原数  ”如:1001010110

0101001101

如果对它们进行AND运算,结果是0001000100

(即同真为真(1),否则为假(0))

         CALL(调用)“CALL something”:CALL指令将当前的相对地址(IP)压入栈中,并且调用CALL 后的子程序。

          CDQ:通常出现在除法前面,作用是将EDX的所有位变成EAX最高位的值,

如当EAX>=80000000h时,其二进制最高位为1,则EDX的32位全被赋值为1,即FFFFFFFF

EAX<80000000,则其二进制最高位为0,EDX为00000000,然后将EDX和EAX组成新数(64位):FFFFFFFF 80000000

         CMP(比较)CMP 目标数,原数。

         DEC(自减)DEC something;dec用来自减一。

         DIV(除)DIV 除数;将EAX除以除数(无符号除法),被除数通常是EAX,结果也储存在EAX中,而被除数对除数取的模存在除数中。

         IDIV(整数)IDIV 除数;与DIV相似,只是是有符号的除法。

         IMUL(整乘)IMUL 数值/IMUL 目标寄存器、数值、数值/IMUL 目标寄存器、数值。

         INC(自加)INC something:将值加一。

         INT:int 目标数;目标数必须是一个整数,INT指令是调用程序对硬件控制,不同的值对应着不同的功能。

         JUMPS(跳转) JA 大于就跳转(无符号)( CF=0 and ZF=0 )

                       JB  小于就跳转(无符号)( CF=1)

                        JE  相等就跳转(ZF=1)

                        JG  大于就跳转(有符号)(ZF=0 and SF=OF“SF=Sign Flag

                        JGE  大于或等于就跳转(有符号)(SF=OF)

                        JL   小于就跳转(有符号)(SF!=OF)

                        JMP 强制跳转

                        JNE  不等于就跳转(ZF=0)

      LEA(有效地址传送):LEA目的数、源数;如:lea eax,dword ptr [4*ecx+ebx]

eax赋值为 4*ecx+ebx

MOV(传送)MOV目的数,源数:将源数赋值给目的数,并保持源数值不变。

MUL(乘法)MUL数值(与IMUL一样,但MUL可以乘无符号数)

NOP(无操作):不做任何事。

OR(逻辑或):OR目的数,源数。只有当两边同为0时其结果为0,否则为1。

POP:POP目的地址:将栈顶第一个字传送到目的地址。

PUSH:POP的相反操作。

REP/REPE/REPZ/REPNE/REPNZREP/REPE/REPZ/REPNE/REPNZ ins;重复上面的指令:直到CX=0。ins必须是一个操作符,比如CMPS、INS、LODS、MOVS、OUTS、SCAS 或 STOS  。

RET(返回)  RET/RET digit;RET指令的功能是从一个代码区域中退出到调用CALL的指令处。RET digit在返回前会清理栈   .

SUB(减):SUB目的数,源数:将源数减去目的数,并将结果储存在目的数中

TEST:TEST操作符、操作符:这个指令主要用于”TEST EAX, EAX”,它执行与AND相同的功能,但是并不储存数据。如果EAX=0就会标记ZF,如果EAX不是0,就会清空ZF  。

XOR(异或):XOR目的数,源数:如果两个值相等,则结果为0,否则为1。

7、

逻辑操作符:AND,OR,XOR,NOT.

一个简单的实例来了解PE文件                                                                              

 1、

      PE文件是Windows操作系统下使用的可执行文件格式  PE文件是指32位可执行文件,也称为PE32.64位的可执行文件称位PE+或PE32+。

PE文件结构一般如上图所示。

PE文件的执行:当一个PE文件被执行时,PE装载器首先检查DOS header里的PE header的偏移量,如果找到,则直接跳转到PE header的位置。第二步要做的就是检查PE header是否有效,如果该PE header有效,就跳转到PE header的尾部。PE装载器执行完第二步后开始读取节表中的节段信息,并采用文件映射的方法将这些节段映射到内存,同时附上节表里指定节段的读写属性。PE文件映射入内存后,PE装载器将继续处理PE文件中类似 import table (输入表)的逻辑部分。

2、

文件加载到内存文件中使用了偏移,内存中使用了VA(虚拟地址)来表示位置;VA指进程虚拟内存的绝对地址,RVA(相对虚拟地址)是指从某基准位置(ImageBase)开始的相对地址

RVA+ImageBase=VA;PE头内部信息大多是RVA形式。当PE文件被执行时,PE装载器会为进程分配4GB的虚拟地址空间,然后把程序所占用的磁盘空间作为虚拟内存映射到这个4GB的虚拟地址空间中。一般情况下,会映射到虚拟地址空间中的0X400000的位置。

每个CPU拥有唯一的Machine码;

PE文件把代码,数据,资源等依据属性分类到各节中储存;NumberOfEsctions指文件中存在的节段(又称节区)数量,也就是节表中的项数。该值一定要大于0,且当定义的节段数与实际不符时,将发生运行错误;

SizeOfOptionalHeader用来指出IMAGE_OPTIONAL_HEADER32结构体的长度。PE装载器需要查看SizeOfOptionalHeader的值,从而识别IMAGE_OPTIONAL_HEADER32结构体的大小;IMAGE_NT_HEADERS结构最后一个成员就是IMAGE_OPTIONAL_HEADER32。

Characteristics用于标识文件的属性,文件是否是可运行的状态,是否为DLL文件等信息。

TimeDateStamp:PE文件的创建时间,一般有连接器填写。

PointerToSymbolTable:COFF文件符号表在文件中的偏移。

NumberOfSymbols:符号表的数量。

3、

必须注意点:

1、IMAGE_OPTIONAL_HEADER32时,magic码为10B,为IMAGE_OPTIONAL_HEADER64时,magic码为20B。

2、ddressOfEntryPoint持有EP的RVA值。该值指出程序最先执行的代码起始地址。

3、一般来说,使用开发工具(VB/VC++/Delphi)创建好EXE文件后,其ImageBase值为00400000,DLL文件的ImageBase值为10000000(当然也可以指定其他值);执行PE文件时,PE装载器先创建进程,再将文件载入内存,然后把EIP寄存器的值设置为ImageBase+AddressOfEntryPoint

4、PE文件的Body部分被划分成若干节段,这些节段储存着不同类别的数据。FileAlignment指定了节段在磁盘文件中的最小单位,而SectionAlignment则指定了节区在内存中的最小单位(SectionAlignment必须大于或者等于FileAlignment)

5、PE文件加载到内存时,SizeOfImage指定了PE Image在虚拟内存中所占用的空间大小,一般文件大小与加载到内存中的大小是不同的。

6、SizeOfHeader用来指出整个PE头大小。该值必须是FileAlignment的整数倍。第一节段所在位置与SizeOfHeader距文件开始偏移的量相同。

7、Subsystem值用来区分系统驱动文件(*.sys)与普通可执行文件(*.exe,*.dll);Subsystem成员可拥有值。

8、数据目录,有地址(VirtualAddress)有大小(Size),其数组定义的一定是一个区域,数组每项都有被定义的值,不同项对应不同数据结构。

9、NumberOfRvaAndSizes用来指定DataDirectory的数组个数,PE装载器需要通过这个值来识别数组个数。

4、

PE文件有不的节段:code(代码)(执行,读取),data(数据)(非执行,读取),resource(资源)(非执行,读取)。节段头是由IMAGE_SECTION_HEADER结构体组成的数组,每个结构体对应一个节段。

VirtualAddress(内存中节段起始地址(RVA))与PointerToRawData(磁盘文件中节段起始位置)不带有任何值,分别由(定义在IMAGE_OPTIONAL_HEADER32中的)SectionAlignment和FileAlignment确定。

                                                                           (基础不好,感觉跳跃太大,自己有待努力呀!)

 

实例破解

(英文,感觉自己好弱,英语还有待强化啊!)

  运用工具0D,破解软件功能限制。

打开About PixtopianBook,将软件载入OD:

1、破解Group限制:在其弹出消息框后暂停OD,此时状态栏显示:暂停,此时需要返回到程序领空,快捷键Alt+F9,然后点击消息框“ 确定” 此时状态栏显示:‍返回到用户;成功返回到程序领空,向上翻。看到了一个MessageBox,这就是刚才确定的那个消息框。“Retn 0xC”这个命令将带我们返回到调用CALL处。所以我们继续向下执行。进行retn,跳出call,返回到调用处,这个Call就是刚才进入的Call,若能跳过这个Call,就能避免跳出消息框。查看这个ascii码,是消息框的标题和内容,在这里被压入栈,等待调用。这里有一个cmp,比较eax与3大小(即Group是否等于3),如果小于就跳转到(JL)00408B34,如果已经有3个Group了,就执行call弹出未注册消息框将JL(小于则跳转)改为jmp(强制跳转)。这样就成功跳过了GROUP验证,将其保存。‍

2、破解联系人限制:弹出消息框后暂停,Alt+F9执行到用户代码,点击确定,跳转另一个位置,向上翻,看到同样的MessageBox, 通过retn跳出call,回到调用处,向上翻,这个call调用了MessageBox,弹出了消息框;这句话同看到的一样,确定程序在这里将其压入栈;比较eax与4的大小(联系人是否已经有4个),如果小于等于(JL)4个,那就跳过消息框,否则弹出未注册消息框。同样修改jl为jmp,强制其跳转,保存。

3、更改版本信息:标题,版本文字在代码区是找不到的,直接在内存中找,输入查找关键字UNREGISTERED,如果ASCII没有搜索到就用UNICODE,记录下004D4830,在dump面板跳转,跳转之后成功找到需要修改的内容,编辑 想写的字符。

4、更改DIY标题:在内存中查找,在弹出的搜索框里输入关键字:(UNREGISTERED VER,记下004E4BE6,在dump窗口跟随,找到需要修改的字符然后编辑。

5、更改提示注册文字:在内存中搜索:首先尝试UNICODE,没有搜索到结果,再尝试ASCII搜索,记录下位置48F974,并跳转到该处:用同样的方法编辑ASCII码,保存。

6、结尾:一直显示welcome信息:通过上面的操作已知注册文字在48F974处,在dump(数据窗口)窗口右键跳转到48F974,需要知道程序哪一段调用了这段字符串,右键选择查找参考(Ctrl+R),找到一处引用,我们双击进入,来到代码位置,上面有一处cmp和jnz(cmp与jnz组合代表:如果不相等,则跳转),如果ebp等于907,则将这串字符压入栈(可以猜测,907代表未注册),我们根据跳转向上翻,又有一处cmp和jnz,意思是如果ebp不等于906,就要跳转回0040C22F处。(可以猜测,906代表注册过)在0040C235的jnz处进行强制跳转,让其不会将这串字符压入栈,保存。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值