我想创建读取汇编指令的代码(仅限x86)并在其他内存位置重新创建它们以生成钩子代码。就像,我想挂钩函数X所以我需要用跳转修补它的(至少)第一个字节和我替换的每个指令(根据汇编代码可能有所不同)(部分或不是)我需要在内存中重新创建我的块,然后添加一条指令,从我没有触摸的下一条指令的偏移量跳回到原始函数X.你可能知道我在说什么,因为它对许多人来说并不新鲜。我不想制作一个完整的完美程序,但我想制作一个完全可扩展的代码库,它将使用一棵树,我将在下面解释。首先让我们想象一些指示:
对于这种情况,我会有一棵看起来像
的树 Tree
|
|
0x12
/ \
B 0x13
|
A
因此,当代码解析一条指令时,它会尝试使用最长的前缀到达指令,如果失败则可以停止或失败,或者在树中尝试上面的指令。
想要做出类似这样的事情的原因是我可以稍后使用dll提供的指令进行扩展,这是我正在做的事情的必要条件,因为我希望能够更快地发布代码来处理90%的指令和只有在我将来需要的情况下才能照顾那些更先进的。
所以,现在我的问题是:处理代码指令的DLL需要的确切完整信息是什么? 喜欢:
我还想问一下树结构是否正常,或者我是否会遇到问题。
所以,基本上我想请你帮忙决定创建最通用的可能代码所需的信息是什么:
给定一个地址,解析其汇编指令,并根据指令调用将复制这些指令的dll中的函数指针。
所以,有点像
void* copy_instructions(void* address,int& len)
{
int bytes_copied = 0;
void* instructions = block of bytes // don't care about the implementation
do
{
void (*copy_instruction)(void*,int*) = get_a_handler_to_instruction_at(address) // this function will use the tree structure and retrieve a function from a dll
if(copy_instruction != NULL)
int len = 0;
void* instruction = copy_instruction(void* address,&len,...) // I want to know how to make this function complete in terms of what it need for every case
if(!instruction)
fail
instructions += instruction // don't care about the implementation
address += len
bytes_copied += len
else
fail
}
while(bytes_copied < 5)
add_instructions_jump_to(instructions,address + bytes_copied)
len = bytes_copied;
return
}
我的问题是:
完整的“copy_instruction”函数标题怎么样? 上面提到的树是否可以实现“get_a_handler_to_instruction_at”或者我需要其他东西。
答案 0 :(得分:3)
为了挂钩你需要的功能:
Jcc
,JMP near
,CALL near
,JMP/CALL qword ptr [RIP+something]
,{{ 1}}),如果是这样,则为目标地址。MOV EAX, dword ptr [RIP+something]
的最常见情况)或甚至16位),这对于简单的直接修补来说是不够短的。在这种情况下,您需要使用较长的相对地址重新组合此类指令(这将需要插入/更改指令前缀或更改Mod / RM / SIB字节)。请记住,相对地址是相对于指令的结尾(或IOW,下一条指令的开始),这意味着如果调整后的指令比原始指令长,则相对地址必须考虑指令长度差异为好。理想情况下,当你覆盖的原始指令彼此jmp时,你也应该准备好处理这个案例。您不希望他们的副本跳回到覆盖的代码。Jcc
指令,跳转到原始函数中的第一个未触及(通过覆盖)指令。在此之后,在大多数情况下,挂钩应该正常工作。如果编译器生成的任何其他代码需要原始指令在原始位置并保持不变,则会出现问题。
对于数据结构,您将替换原始代码的JMP
个字节。对于32位跳转,N
为5。那些N
字节将对应于最多N
个原始指令。您需要完整地保存那些1到N个指令(每个指令最多15个字节,IIRC),然后解析,可能调整并存储在新位置。你这里真的不需要一棵树,一个数组就足够了。每条指令的元素。简单。但是这些代码需要仔细编写和调试/测试。
请参阅相关问题。可能有宝贵的细节。
编辑:回答主要问题:
我认为,“复制”所有指令(copy_instructions())的主要功能可能确实是在您定义它时定义的。但是,您可能希望从中返回错误代码,以防它失败(分配内存或反汇编未知指令或其他内容)。它可能会有所帮助。我无法看到你/呼叫者需要的其他内容。