原文:https://www.pediy.com/kssd/pediy10/77856.html
最近在做对程序自动跟踪调试的工作。在用的反汇编引擎:libdasm1.5
但是在处理CALL语句时出现问题:
例:
00401000 . E8 0B000000 call 00401010
00401005 . /E9 16000000 jmp 00401020
在网上查了下,说是0x401010 = 0x00401005 + 0x0B,
但是用libdasm反汇编出的语句是
call 0x15
怎么会这样呢?
另:
如何通过CALL XXXX判断XXXX是用户自己定义的函数,还是系统调用呢?
初步想是通过代码段地址范围来判断,但是动态载入的DLL呢,各位有什么其他好办法吗?
谢谢!
问题太简单,可能也有点偏,请各位提点思路,不胜感激!
反汇编成call 0x0B还是可以理解的,因为E8和E9的参数都是16/32为的相对偏移地址,符号扩展后加到EIP(也就是下条指令的地址)上去就是新的EIP,也就是翻译出来给我们看的地址。
call 0x15没有道理啊!你确定的确是被翻译成了call 0x15?又没有什么运行的例子什么的?发出来一起研究研究?
Call xxx的对xxx的判断,你可以试试这个方法(菜鸟愚见,望高手毋笑)?
1、首先判断该地址是否在pe文件的.txt/.code代码映射后的空间范围类,是则表示跳转后的地址应该是程序自身。
2、如果不是1,读取pe文件的所有import的函数的地址,逐个比较。
3、如果还不是,读取实例所有模块,比较地址。
显示格式不同,
显示格式是: call $+offset //这个$ 指本条指令边界
call 0x15 // call 00401010 对于$ 来说是偏移 0x15
call 0xb5de // call 0040c5f0 对于$ 来说是偏移 0xb5de
call 0x931 // call 00401951 对于 $ 来说是偏移 0x931
编码是一样的,只是显示不同而已
再弱问一下,那我是不是可以通过call指令的near或far来区分后面的操作数呢?
看了egogg推荐的coder table,发现CALL指令对应的代码只有:E8,FF,9A(这个还没见过)
那我如果要区分CALL XXXX中XXXX的范围,
例如:
if(E8)
{
if(min<XXXX<max)
blablabla;
}
else if(FF)
{
if(min<DS:[XXXX]<max)
blablabla
}
else
{
(9A????)
}
想法太菜,各位见笑!
near调用时,CALL的操作数确实就是跳转地址,但是当是far时,或者需要取DS:[XXXX],或者类似:CALL EDI,再取EDI的值,有点麻烦。
您说的libdasm的特点我不太明白指的是什么?
typedef struct _INSTRUCTION { int length; // Instruction length enum Instruction type; // Instruction type enum Mode mode; // Addressing mode BYTE opcode; // Actual opcode BYTE modrm; // MODRM byte BYTE sib; // SIB byte int modrm_offset; // MODRM byte offset int extindex; // Extension table index int fpuindex; // FPU table index int dispbytes; // Displacement bytes (0 = no displacement) int immbytes; // Immediate bytes (0 = no immediate) int sectionbytes; // Section prefix bytes (0 = no section prefix) OPERAND op1; // First operand (if any) OPERAND op2; // Second operand (if any) OPERAND op3; // Additional operand (if any) PINST ptr; // Pointer to instruction table int flags; // Instruction flags short eflags_affected; // Process eflags affected short eflags_used; // Processor eflags used by this instruction int iop_written; // mask of affected implied registers (written) int iop_read; // mask of affected implied registers (read) } INSTRUCTION, *PINSTRUCTION;
typedef struct _OPERAND { enum Operand type; // Operand type (register, memory, etc) int reg; // Register (if any) int basereg; // Base register (if any) int indexreg; // Index register (if any) int scale; // Scale (if any) int dispbytes; // Displacement bytes (0 = no displacement) int dispoffset; // Displacement value offset int immbytes; // Immediate bytes (0 = no immediate) int immoffset; // Immediate value offset int sectionbytes; // Section prefix bytes (0 = no section prefix) WORD section; // Section prefix value DWORD displacement; // Displacement value DWORD immediate; // Immediate value int flags; // Operand flags } OPERAND, *POPERAND;
呵呵,非常感谢egogg。
明白一些您的意思,利用引擎已得到信息确实可以减少很多工作。
感谢您的精彩建议。