linux内联汇编,绕行和GCC内联汇编(Linux)

这个项目是否开发了一个“框架”,允许其他人在不同的二进制文件中挂钩不同的功能?或者只是你需要挂钩你有这个特定的程序?

首先,让我们假设你想要第二件事,你只需要一个二进制函数,你想挂钩,编程和可靠.普遍这样做的主要问题是,可靠地做到这一点是一场非常艰难的比赛,但如果你愿意做出一些妥协,那么它肯定是可行的.另外我们假设这是x86的事情.

如果要挂钩函数,可以使用多种选项. Detours的内容是内联修补.他们对Research PDF document中的工作方式有一个很好的概述.基本的想法是你有一个功能,例如

00E32BCE /$8BFF MOV EDI,EDI

00E32BD0 |. 55 PUSH EBP

00E32BD1 |. 8BEC MOV EBP,ESP

00E32BD3 |. 83EC 10 SUB ESP,10

00E32BD6 |. A1 9849E300 MOV EAX,DWORD PTR DS:[E34998]

...

...

现在用函数CALL或JMP替换函数的开头,并保存你用补丁覆盖的原始字节:

00E32BCE /$E9 XXXXXXXX JMP MyHook

00E32BD3 |. 83EC 10 SUB ESP,10

00E32BD6 |. A1 9849E300 MOV EAX,DWORD PTR DS:[E34998]

(注意我覆盖了5个字节.)现在使用与原始函数相同的参数和相同的调用约定来调用函数.如果你的函数想要调用原始函数(但它没有),你创建一个“trampoline”,1)运行被覆盖的原始指令2)jmps到原始函数的其余部分:

Trampoline:

MOV EDI,EDI

PUSH EBP

MOV EBP,ESP

JMP 00E32BD3

就是这样,你只需要在运行时通过发出处理器指令来构造trampoline函数.这个过程的难点在于让它可靠地运行,任何函数,任何调用约定和不同的OS /平台.其中一个问题是,如果要覆盖的5个字节在指令的中间结束.要检测“指令的结尾”,您基本上需要包含反汇编程序,因为在函数的开头可以有任何指令.或者当函数本身短于5个字节时(一个总是返回0的函数可以写成XOR EAX,EAX; RETN只有3个字节).

大多数当前的编译器/汇编器产生一个5字节长的函数序列,正是为了这个目的而挂钩.看到MOV EDI,EDI?如果你想知道,“他们为什么要将edi移到edi?那什么都不做!?”你是完全正确的,但这是prolog的目的,正好是5字节长(不是在指令的中间结束).请注意,反汇编示例不是我编写的,它是Windows Vista上的calc.exe.

钩子实现的其余部分只是技术细节,但它们可以给你带来许多小时的痛苦,因为这是最难的部分.您在问题中描述的行为:

void MyInstallRules(void)

{

if(PreHook() == block) //

return;

int * val = InstallRules(); //

PostHook(val); //

}

看起来比我描述的更糟(以及Detours的作用),例如你可能想要“不调用原始”但返回一些不同的值.或者两次调用原始功能.相反,让你的钩子处理程序决定它是否以及在何处调用原始函数.此外,您不需要两个处理程序函数用于挂钩.

如果您对此所需的技术(主要是装配)知之甚少,或者不知道如何进行挂钩,我建议您研究一下Detours的作用.挂钩你自己的二进制文件并拿一个调试器(例如OllyDbg)来查看汇编级别它究竟做了什么,放置了什么指令以及放在哪里. this tutorial也可能会派上用场.

无论如何,如果你的任务是挂钩特定程序中的某些功能,那么这是可行的,如果你遇到任何麻烦,请再次询问.基本上你可以做很多假设(如函数prologs或使用的约定),这将使你的任务更容易.

如果你想创建一个可靠的钩子框架,那么仍然是一个完全不同的故事,你应该首先为一些简单的应用程序创建简单的钩子.

另请注意,此技术不是特定于操作系统,在所有x86平台上都是相同的,它可以在Linux和Windows上运行.什么是特定于操作系统的是您可能必须更改代码的内存保护(“解锁”它,因此您可以写入它),这是通过Linux上的mprotect和Windows上的VirtualProtect完成的.调用约定也是不同的,这就是你可以通过在编译器中使用正确的语法来解决的问题.

另一个麻烦是“DLL注入”(在Linux上它可能被称为“共享库注入”,但术语DLL注入是众所周知的).您需要将代码(执行挂钩)放入程序中.我的建议是,如果可能,只需使用LD_PRELOAD环境变量,您可以在其中指定一个库,该库将在运行之前加载到程序中.这已经在很多时候被描述过了,就像这里:What is the LD_PRELOAD trick?.如果你必须在运行时这样做,我担心你需要使用gdb或ptrace,在我看来这很难(至少是ptrace的事情)去做.但是,您可以阅读例如this article on codeproject或this ptrace tutorial.

我还找到了一些不错的资源:

还有一点:这种“内联修补”并不是唯一的方法.甚至有更简单的方法,例如如果函数是虚函数或者它是库导出函数,则可以跳过所有汇编/反汇编/ JMP事物,只需替换指向该函数的指针(在虚函数表或导出的符号表中).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值