前言
哇,一不小心又偷懒了很久。是的,这次我真的是偷懒了,我就承认了怎么样。
回到正题,之前星际争霸快速指令只是进行了内存查找和修改的分析,今天我们来分析一下其中的汇编代表的意义。
很多人看到汇编都会觉得很难,超级复杂,人怎么可能学会呢,其实是思维的问题,转换一下思维,你也能学得很好。
PS:本篇可能有很多啰嗦的文字,但是依然会讲得比较浅显,所以大家不用方张。
上一篇传送门
文明转帖,若需要转帖请注明出处,谢谢。
基础知识
一些思维方式
1.不要畏惧未知。
未知往往是收获而不是羞耻,人最多的东西永远是不知道的。碰到不知道或者不明白的东西,一定要去弄清楚,滴水穿石的力量是很可怕的。
2.不要害怕翻阅答案
在学习破解或者CM练习的时候,不要害怕去搜索别人的答案,觉得自己总是在看答案。你刚学,什么都不会是正常的,就是要去多看看别人的思路,慢慢的,你就会有思路了。
3.要勤于总结
所谓的总结,不仅仅针对于失败,成功也可以总结。比如此次怎么快速的定位到了,或者失败的原因是什么,下次应该怎么避免失败,别人这次用了什么新工具。只要总结,你就是有得到东西。
4.可以尝试写点博客
尝试把自己的收获或者成果和大家分享,不仅仅帮助了别人,对自己也是很大的帮助。总有人说,我会做,就是不会说。但写博客是一个把你的思维结构化很好的方法,你为了让别人看懂,可能会花费比自己做更多的精力,而且还需要重新整理和巩固基础知识,是非常好的一种方式。
PS:年纪大了有点啰嗦,后面的东西更啰嗦,怕你们看不下去,所以写在前面,这些思维比后面还重要。
PS2:前方超级高能且嫉妒催眠,这不是演习,只是打酱油建议直接跳到实战分析。
汇编知识
在这里稍微简单介绍一下相关的知识点,后面逐句分析
寄存器
顾名思义,就是寄存数据的地方,当然这数据可以包括:指令,内存地址和数据。可以理解为超市门口的寄存柜。你存进去,谁拿纸过去,谁就可以拿。当然他也可以选择把东西拿走,或者是只是看一看。
在汇编中主要使用的寄存器有EAX、EBX、ECX、EDX、ESI、EDI、ESP、EBP。(其实有16个....)
其实寄存器要深究还是蛮复杂的,有兴趣的可以自己去找找资料,这里不讲太深。
栈
一种用于存放数据的线性列表。
我看到的对栈的描述最好的解释就是扑克牌。我们把数据当成扑克牌,每人手里的牌是寄存器的数据。栈相当于未摸扑克牌的集合体。你盖回去的时候,只能盖在最上面,你拿牌,也只能从最上面拿。
栈的原则,先进后出,后进先出。
PUSH指令
将寄存器里的值放到栈里。
由于寄存器的数量有限,有时候我们需要使用其中一个寄存器,但是它又已经存放了别的数据那怎么办呢?这时候就可以先把寄存器原先的值push到栈里,待我们使用完寄存器,再把原先的值重新放到之前的寄存器中,这样程序就可以依然正常运行了。
按扑克牌比喻可以理解为,假如你拿牌拿多了,需要再放回去,放哪里呢?放第一张。
例 PUSH EAX。将eax寄存器中的值放入栈里。
POP指令
取出栈里的第一个元素到指定寄存器。
按扑克牌比喻可以理解为,XX拿一张牌到手上。
例POP EAX。将栈顶(就是最上面)数据存放到eax中,同时在栈中删除这条数据(因为牌被拿走了嘛)。
MOV指令
赋值指令。
例mov eax,ebx,其实很好记,就和别的语言一样int eax = ebx。顺着读就行,意思是将ebx值赋给eax
CMP指令
比较指令,并将比较的值存入标志位。(暂时可以理解就是存到另外的地方)
一般在跳转之前使用,因为跳转J**会根据标志位来判断是否跳转。
JNE指令
标志位ZF=0时跳转。可以简单记做前面的CMP不相等就跳转。(主要还是要看ZF)
进制
进制其实就是进(一)制,逢X进1,主流的进制为:二进制、八进制、十进制、十六进制。分别对应:逢2进1、逢8进1、逢10进1、逢16斤1。
一般在汇编里,主要使用的是十六进制。对应的16个数字分别是0~9,A、B、C、D、E、F。(A=10,F=15)
16进制通常前面会加上0x的标志,例0xFF0014
ASCii码
美国信息交换标准代码,是基于拉丁字母的一套电脑编码系统。
可以理解为电脑的字典。所有的数据,在电脑里都是数字,那么电脑怎么知道显示给我们看字呢,就是通过这个字典。电脑会拿到数字去比对字典中对应什么含义,然后展示给我们对应的字母。(不用死记)
字节
一个英文字母的长度,我们称为一个字节,又叫一个byte。结合ASCii码,我们可以知道,一个字节可以由2位16进制来表示,所以我们的寄存器其实是一次4字节的。(有兴趣的可以去继续思考,bit和byte的关系,你就会明白为啥是32位寄存器了)
实战分析
根据上一篇的星际逻辑来逐行分析。先给一个整体。
push eax 备份之前的寄存器内容,怕出BUG。其实这次的需求不写也行,好习惯。
mov eax,dword ptr ds:[ecx+0x14] 将输入内容读到寄存器eax中
cmp word ptr ds:[eax],0x31 比较输入的值是不是1
jne short 004ECDEB 这跳转你要看你们自己的,跳转到pop eax那一行
mov dword ptr ds:[eax],0x776F6873 内存写入"show"
mov dword ptr ds:[eax+0x4],0x20656D20 内存写入" me "
mov dword ptr ds:[eax+0x8],0x20656874 内存写入"the "
mov dword ptr ds:[eax+0xC],0x656E6F6D 内存写入"mone"
mov word ptr ds:[eax+0x10],0x79 内存写入"y "
pop eax 还原寄存器内容
call 004E6030 调用原来正常逻辑需要调用的方法
ret 返回引用处
第一行push eax,将eax的数据给放到栈中(扑克牌回忆起来)。我们要使用eax,所以先把数据放到栈里,对应倒数第三行的pop eax,把数据还原回eax中。
mov eax,dword ptr ds:[ecx+0x14]
这一句整体含义是,将用户输入的内容的起始地址读取到寄存器中。(初始地址读入之后,会循环向后读取到所有内容)
拆分开,这句变成了关键字mov,寄存器eax,和dword ptr ds:[ecx+0x14],其中mov和eax在基础知识里已经介绍了。
首先dword、ptr、ds都是修饰最后中括号中的地址。
所以我们可以分析出这里的逻辑就是,把后面这个括号里的值[ecx+0x14],赋值给寄存器eax,但是是什么样的值呢?
PS:我知道是ecx+0x14是因为在call方法那里我打断点进去看到了ecx的值就是输入的值+了偏移。
汇编中,如果是直接eax寄存器名称,则是将寄存器的值直接使用;但如果是中括号包含着的,就是寄存器中的值当成内存地址,取在内存地址中的数值。
- dword:代表数据长度为四字节。相对的还有word两字节和byte单字节。
- ptr代表指针,这里可以理解为对寄存器读取的是内存地址中值的申明。
- ds(Data Segment)代表数据段寄存器,代表是括号中的地址是相对于DS开始偏移。内存是动态的,当分配完数据段内存之后,我们可以根据数据段寄存器来使用偏移得到动态地址。
所以:整句话变成了,取ecx+0x14内存中的值的4个字节(8位16进制)放到eax中。
觉得复杂?没事,我们来做一个通用步骤:
- 先找关键字,如mov,cmp之类。
- 再找分隔符“,”,如果有的话,分隔符前后就是两个参数。
- 确定主语,一般就是分割符之前和整个语句最后两处是主语。
- 接下来就是分析主语修饰词(语文真的不好,不知道啥定补状)
按照整个方法试试下面这一句:
cmp word ptr ds:[eax],0x31
关键字:CMP。主语:[eax]和0x31。
- CMP比较指令
- word为两字节(两字节是因为容错,如果单字节,打123,也会识别。想想为啥不能四字节)
- ptr代表eax内存地址中的值
- ds仍然是代表偏移。
结合上一句,我们将用户输入的值的地址传到了eax中,所以现在读取[eax],代表用户输入的值,用户输入的值和0x31对比,0x31对应ascii中的值代表就是“1”,这里其实就是比较用户输入值是否为1。
接下来下一句就是针对于CMP的判断跳转,没啥好说的吧,如果之前判断相等就不跳转。也就是如果相等继续执行下面逻辑。
再来下一句:
mov dword ptr ds:[eax],0x776F6873
关键字:mov。主语:[eax]和0x776F6873
- mov为赋值指令
- dword四字节
- ptr代表eax内存地址中的值
- ds仍然是代表偏移
现在应该很好看懂了吧,但是要注意一点,Intel的芯片目前都是小端模式存储数据,所以数据是逆向的。
写入的时候要注意逆向写入,查ASCII可以知道,0x77=w,0x6F=o,0x68=h,0x73=s。
具体啥叫小端模式可以百度《大小端模式》,不感兴趣的话直接记住逆向输入即可。
剩下的都是类似的东西了,大家自己应该可以一行行分析了吧。
结尾
总算是写完了,这一篇概念真是多得我自己都晕头转向的,如果有兄台真心看完了,我觉得你肯定是可以的,坚持下去。
大家可以按照这种方式往后补上额外的作弊,比如2开地图之类的。
另外附上完整修改版的快速作弊,即1金钱,2开地图,3建造速度。(是我以前弄的,有个小BUG,看大家能不能发现)
链接:https://pan.baidu.com/s/1gOPrZaZR32J0u1W_cn4vMA
提取码:za4c
请支持正版,支持正版,支持正版!
提前祝大家中秋快乐!