这可能是一个非常简单的问题,因为我不太习惯OllyDBG的反汇编程序的语法外观。

是否执行以下汇编程序语句:

MOV EAX, DWORD PTR [ESI + 14]


大致翻译为以下C代码: />
我是否正确理解了语法,或者我误解了?

评论

您可能正在寻找DWORD eax = *(DWORD *)((char *)esi + 0x14)。 (我不确定,但是Olly默认情况下可能以十六进制而不是十进制显示偏移量。)

那么eax将包含esi + 0x14所指向的值?

是的,DWORD PTR表示将从该地址开始占用四个字节。

啊,谢谢!但是,如果您要这样,以后可以将其用作指针?您介意将其转换为答案,以便让我接受吗? :)

在您的问题中,eax =&(esi + 0x14);应该是eax = *(esi + 0x14);。它在引用它,而不是引用它。

#1 楼

DWORD PTR [expression]语法的意思是“获取expression的值,将其解释为一个地址,并从该地址开始访问4(DWORD的大小)字节”。但是汇编数据类型与C的数据类型有很大不同,因此可以通过这种方式访问​​许多C类型。

您提供的指令基本上等效于C代码:

该指令可用于访问4个连续字节,无论这些字节的C类型是什么-在上面的行中,您可以(在32位系统上)将dword_t定义为intfloatvoid *或其他适当大小的类型,它仍将以相同的方式工作,只是从一个地方到另一个地方的位和字节。使用相当智能的编译器,只要它们的长度足够小,它甚至可以一步一步地读取整个结构或数组。如我所愿,指针是否可以满足您的需求?


正如我所说,无法仅从上下文中得知这些字节的原始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
选项->代码

例如MASMIDEALHLA

反汇编代码的外观还有很多其他选择。单击周围。这些更改可以立即很容易地找到正确的更改。在其他地方,例如以下拆卸说明中的详细说明,例如以10为基数的数字-然后以点号结尾。例如。 0x10(16.)


(在这里,我大步走……)

在阅读代码时

英特尔)

像x86asm.net上的表格和Sandpile这样的表格,在使用汇编代码时都是绝对有价值的资产。但是,还应该有:



英特尔®64和IA-32架构软件开发人员手册,第1卷:基本体系结构。
英特尔®64和IA-32架构软件开发人员手册。手册,第2卷(2A,2B和2C):指令集参考,AZ。
…等(还有一些收集卷。)

来自英特尔®64和IA-32 《体系结构软件开发人员手册》。

有很多很好的章节和描述,说明如何将系统缝合在一起以及操作如何影响整个系统,如寄存器,标志,堆栈等。 《开发人员》卷中的AT&T0xh


如前所述,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 |
+-------------+-----------------+---------------------------+


其中0x140xfe是: >
要进一步发展此概念,您可以创建另一个带有寄存器的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