gpt4 book ai didi

assembly - 克隆汇编指令所需的完整信息是什么

转载 作者:行者123 更新时间:2023-12-04 05:58:12 24 4
gpt4 key购买 nike

我想制作读取汇编指令(仅限 x86)并在其他内存位置重新创建它们以制作 Hook 代码的代码。就像,我想 Hook 函数 X 所以我需要用跳转来修补它的(至少)第一个字节和我替换的每条指令(可以根据汇编代码而变化)(部分或不部分)我需要在内存中重新创建我的块,然后添加一条指令,从我没有触及的下一条指令的偏移量跳回原始函数 X。你可能知道我在说什么,因为它对很多人来说并不新鲜。我不想制作一个完整的完美程序,但我想制作一个完全可扩展的代码库,该代码库将使用我将在下面解释的树。首先让我们想象一些指令:

  • A - "0x12 0x13 .."这个指令有 4 个字节,前两个是静态的。
  • B - "0x12 ."该指令有 2 个字节,第一个是静态的。

  • 对于这种情况,我将有一棵树看起来像
        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”还是我需要其他东西。

    最佳答案

    为了 Hook 一个函数,你需要:

  • 了解它的接口(interface)(调用约定、参数号和类型,所有这些)。编译器在优化代码时可能会内联函数或绕过接口(interface)。如果是这种情况,我不知道如何最好地处理它。您可能需要调整代码,以便通过指向函数的 volatile 指针调用该函数,试图说服编译器该指针可能随时更改其值并指向具有相同参数的任何其他函数,这是不明智的更改函数的序言和结尾。禁用优化可能是另一种选择。所有这些都是为了避免原始函数和新函数在接收参数和返回方式方面不兼容的情况。但是,如果这是导出的函数之一,编译器显然不会更改任何内容,因为它会破坏代码。
  • 知道它的地址。
  • 最小程度地反汇编函数的第一条指令,您将使用跳转指令覆盖新代码。反汇编时,您必须找出:指令长度(为此,您需要正确解析所有指令前缀、所有操作码字节、所有 Mod/Rm/SIB 字节、所有位移和所有立即操作数字节;一些逻辑 + 查找表将有所帮助),该指令是否将控制转移到与指令指针相关的位置或访问数据(例如 JccJMP nearCALL nearJMP/CALL qword ptr [RIP+something]MOV EAX, dword ptr [RIP+something] ),如果是这样,目标地址。
  • 知道原始指令的副本地址。理想情况下,您应该在解析指令后为副本分配内存,但您可以(并且可能应该)预分配更多内存以简化您的生活。
  • 将原始指令复制到新位置,并根据需要通过这些指令的新旧位置之间的差异调整其中的相对地址。请注意,原始指令可能会在其中使用非常短的相对地址(例如 8 位(最常见的 Jcc 情况)甚至 16 位),这对于简单的直接修补来说不够短。在这种情况下,您需要使用更长的相对地址重新组装此类指令(这将需要插入/更改指令前缀或更改 Mod/RM/SIB 字节)。请记住,相对地址是相对于指令的结束(或 IOW,下一条指令的开始),这意味着如果调整后的指令比原始指令长,则相对地址将必须考虑指令长度差异好。理想情况下,您还应该准备好处理您覆盖的原始指令相互 jmp 的情况。您不希望他们的副本跳回被覆盖的代码。
  • 添加 JMP跳转到原始函数中第一个未触及(通过覆盖)指令的指令。

  • 在此之后,在大多数情况下 Hook 应该可以正常工作。如果编译器生成的任何其他代码期望原始指令位于其原始位置且未更改,则会出现问题。

    至于数据结构,你替换 N原始代码的字节数。 N 32 位跳转为 5。那些 N字节最多对应于 N原始说明。您需要完整地保存这 1 到 N 条指令(每条指令最多 15 字节长,IIRC),然后解析、可能调整并存储在新位置。你在这里真的不需要一棵树,一个数组就足够了。每条指令一个元素。简单的。但有相当多的代码需要仔细编写和调试/测试。

    请参阅相关问题。可能有有值(value)的细节。

    编辑:回答主要问题:

    我认为,“复制”所有指令的主要功能(copy_instructions())确实可以按照您的定义进行定义。但是,如果它失败(分配内存或反汇编未知指令或其他东西),您可能希望从中返回错误代码。它可能会有所帮助。我看不到您还需要从/为来电者提供什么。

    关于assembly - 克隆汇编指令所需的完整信息是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9257276/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com