是否执行以下汇编程序语句:
MOV EAX, DWORD PTR [ESI + 14]
大致翻译为以下C代码: />
我是否正确理解了语法,或者我误解了?
#1 楼
DWORD PTR [expression]
语法的意思是“获取expression
的值,将其解释为一个地址,并从该地址开始访问4(DWORD
的大小)字节”。但是汇编数据类型与C的数据类型有很大不同,因此可以通过这种方式访问许多C类型。您提供的指令基本上等效于C代码:
该指令可用于访问4个连续字节,无论这些字节的C类型是什么-在上面的行中,您可以(在32位系统上)将
dword_t
定义为int
,float
, void *
或其他适当大小的类型,它仍将以相同的方式工作,只是从一个地方到另一个地方的位和字节。使用相当智能的编译器,只要它们的长度足够小,它甚至可以一步一步地读取整个结构或数组。如我所愿,指针是否可以满足您的需求?正如我所说,无法仅从上下文中得知这些字节的原始C类型。您必须查看使用此值的其他地方,并查找特定类型的指标。如果看到它用在
[eax]
或类似的表达式中-可能是指针。如果将其用于更复杂的表达式(例如[eax + ecx]
)中,则两者之一是指针,另一个是该指针的数组索引/字节位移,但是无法确定哪一行是哪个,需要更多上下文。 评论
感谢你的回答!我能否再问一个小小的问题:可以说这样的话很明显:mov eax,DWORD PTR [ecx + esi * 4 + 0x18]是否表示我们有一个结构数组? ecx可以是基本adr,esi * 4是一个元素的大小,而0x18是结构中要访问的成员的偏移量?不是说一定是这样,但是可以吗?提前致谢!
–lfxgroove
13年7月9日在11:06
@lfxgroove:不客气。是的,这是最可能的解释。
– DCoder
13年7月9日在11:25
#2 楼
@DCoder肯定回答了这个问题,因此这里仅是一些注释,或者至少起初只是一个简短的注释,最后变成了一个怪兽。 (带有一些扩展名)。换句话说:operation target, source
其他语法在下面可用(取决于版本):
Options-> Debugging Options- > Disasm
选项->代码
例如
MASM
,IDEAL
和HLA
。反汇编代码的外观还有很多其他选择。单击周围。这些更改可以立即很容易地找到正确的更改。在其他地方,例如以下拆卸说明中的详细说明,例如以10为基数的数字-然后以点号结尾。例如。 0x10(16.)
(在这里,我大步走……)
在阅读代码时
英特尔)
像x86asm.net上的表格和Sandpile这样的表格,在使用汇编代码时都是绝对有价值的资产。但是,还应该有:
英特尔®64和IA-32架构软件开发人员手册,第1卷:基本体系结构。
英特尔®64和IA-32架构软件开发人员手册。手册,第2卷(2A,2B和2C):指令集参考,AZ。
…等(还有一些收集卷。)
来自英特尔®64和IA-32 《体系结构软件开发人员手册》。
有很多很好的章节和描述,说明如何将系统缝合在一起以及操作如何影响整个系统,如寄存器,标志,堆栈等。 《开发人员》卷中的
AT&T
,0x
,h
。如前所述,x86amd和Sandpile是很好的资源,但是当您对指令有所疑问时,手册也是不错的选择。 “指令集参考AZ”。
整行可能类似于:
00406ED6 8B46 14 MOV EAX,DWORD PTR DS:[ESI+14]
; or
00406ED6 8B46 14 MOV EAX,DWORD PTR [ESI+14]
(取决于选项和始终显示默认段。 )
在这种情况下,我们可以将二进制文件拆分为:
有关详细信息,请参见手册。例如。 AZ手册中的“第2章指令格式”。
找到
6.2 STACKS
操作,您将看到:MOV –移动
8B46 14
| | |
| | +---> Displacement
| +------> ModR/M
+--------> Opcode
指令操作数编码
Opcode Instruction Op/En 64-bit Compat Description
…
8B /r MOV r32,r/m32 RM Valid Valid Move r/m32 to r32.
| |
| +---> source
+-------> destination
…
阅读“ 3.1解释指令参考页”以获取有关代码的详细信息。
简而言之,MOV – mov表说:
Op/En Operand1 Operand2 Operand3 Operand4
RM ModRM:reg (w) ModRM:r/m (r) NA NA
指令操作数编码表说:
截面太深
确定。现在,我要深入到这里,但无法阻止自己。 (通常会发现了解构建块有助于理解该过程。)
ModR / M字节为
3.4 BASIC PROGRAM EXECUTION REGISTERS
,二进制形式为:8B : Opcode.
/r : ModR/M byte follows opcode that contains register and r/m operand.
r32 : One of the doubleword general-purpose registers.
r/m32: Doubleword general-purpose register or memory operand.
RM : Code for "Instruction Operand Encoding"-table.
< br字段
REG字段的值
CHAPTER 4 DATA TYPES
转换为MOV
Mod + R / M转换为
0x46
(参考“ 2.1。 5 ModR / M和SIB字节的寻址模式编码”表2-2(在AZ参考中)。 2.告诉我们,在ModR / M字节之后是一个8位值,8位位移字节,应将其添加到
000
的值中。相比之下,如果存在32位位移或寄存器操作码+ ModR / M,则为:是一个1字节的值,应该添加到ESI的值中。在这种情况下
EAX
。请注意,此字节已签名,例如
ESI+disp8
表示ESI
。要使用的段
ESI是指向DS指向的段中数据的指针。
段选择器由三个值组成: 0x0023我们有:
reg : Operand 1 is defined by the reg bits in the ModR/M byte.
(w) : Value is written.
r/m : Operand 2 is Mod+R/M bits of ModR/M byte.
(r) : Value is read.
GDT =全局描述符表
LDT =局部描述符表
段寄存器(CS,DS,SS,ES,FS和GS)旨在容纳代码,堆栈或数据的选择器。这是为了减少复杂性并提高效率。
这些寄存器中的每一个还具有隐藏部分,也称为“影子寄存器”或“描述符缓存”,其中包含基地址,段限制和访问控制信息。当将段选择器加载到段寄存器的可见部分时,处理器将自动加载这些值。
qBASE12078q是线性地址。 ES,DS和SS不在64位模式下使用。
结果
从段地址ESI + disp8读取32位值。示例:
7,6 5,4,3 2,1,0 (Bit number)
0x46: 01 000 110
| | |
| | +---> R/M
| +-----------> REG/OpExt
+------------------> Mod
用C模拟
您的示例的一个问题是
disp8
是整数(严格来说)。但是,该值可以是段地址之一。然后,您必须考虑到每个段都有一个基地址(偏移量),例如:32-bit displacement General-purpose register
+-----> MOV r32,r/m32 +-----> MOV r32,r/m32
| |
8Bh 86h 8Bh C1h
| +--> EAX | +--> EAX
| | | |
+---> 10 000 110 b +---> 11 000 001 b
| | | |
+---+---+ +---+---+
| |
v v
ESI + disp32 ECX
在这种情况下,因为它是ESI,所以段将是DS指向的段。
要在C中进行模拟,您将需要通用寄存器的变量,但是还需要创建段(从何处读取/写入数据。)大致来说,这样的代码可能是这样的:
15 - 3 2 1 - 0 (Bits)
|-------------|-----------------|---------------------------|
| Index | Table Indicator | Requested Privilege Level |
+-------------+-----------------+---------------------------+
其中
0x14
和0xfe
是: > 要进一步发展此概念,您可以创建另一个带有寄存器的
ESI - 0x02
,为寄存器使用定义或变量,添加默认段等。对于基于Intel的体系结构,的方向(作为一个不好的开始):
0x23 0000000000100 0 11 b
| | |
| | +----> RPL : 3 = User land, (0 is kernel)
| +-------> TI : 0 = GDT (GDT or LDT)
+---------------> Index: 4 Multiplied by 8 and added to TI
为了更紧凑的方式,将ptr放弃到
esi
寄存器等,可以查看例如virtualbox的代码库。注意:大多数编译器都需要某种形式的pack指令,以防止在结构中填充位-例如AH和AL确实与AX的正确字节对齐。
评论
我想我现在有一些需要阅读的内容;)非常感谢您提供的信息!
–lfxgroove
13年7月9日在11:30
@lfxgroove:欢迎您:)在C中模拟汇编非常有教育意义(如果习惯于C)。
– Runium
13年7月9日在11:45
我可以想象,从未真正想到过要这样做:)
–lfxgroove
13年7月9日在11:46
码头我还看到我弄乱了最后一个代码块中的#defines。显然应该是CPU.accumulator.r64等。
– Runium
13年7月9日在15:44
评论
您可能正在寻找DWORD eax = *(DWORD *)((char *)esi + 0x14)。 (我不确定,但是Olly默认情况下可能以十六进制而不是十进制显示偏移量。)那么eax将包含esi + 0x14所指向的值?
是的,DWORD PTR表示将从该地址开始占用四个字节。
啊,谢谢!但是,如果您要这样,以后可以将其用作指针?您介意将其转换为答案,以便让我接受吗? :)
在您的问题中,eax =&(esi + 0x14);应该是eax = *(esi + 0x14);。它在引用它,而不是引用它。