今天我有一个想法,试图手动加载编译后的代码。我脑海里想的是读取一个编译后的目标文件并将其存储到一个缓冲区中,获取缓冲区中的位置什么是入口点,获取该元素的地址,并将其转换为函数指针并通过指针调用该函数。但是,我发现了一个障碍:如何从包含编译代码的字节数组中获取主函数(或任意函数)的地址?手动加载已编译的代码
谢谢
P.我知道我可以使用API动态加载,但我想手动执行它...如果这不是一项压倒性的努力。这只是一个概念验证项目,所以我没有问题保持简单! 再次感谢!
今天我有一个想法,试图手动加载编译后的代码。我脑海里想的是读取一个编译后的目标文件并将其存储到一个缓冲区中,获取缓冲区中的位置什么是入口点,获取该元素的地址,并将其转换为函数指针并通过指针调用该函数。但是,我发现了一个障碍:如何从包含编译代码的字节数组中获取主函数(或任意函数)的地址?手动加载已编译的代码
谢谢
P.我知道我可以使用API动态加载,但我想手动执行它...如果这不是一项压倒性的努力。这只是一个概念验证项目,所以我没有问题保持简单! 再次感谢!
如果你使用目标文件或链接库来做这件事,那基本上是手动映射,你可以在这里得到一个相当不错的阅读/参考(但是对于windows):http://pastebin.com/HbWNAV99代码执行存储的缓冲区,这是JIT会做的事情,因此需要预先计算入口点并将缓冲区内存设置为可执行。
您可以在二进制文件中搜索函数序言,它会给你所有的函数,但是你将无法判断哪个函数是入口点。假设你也可以搜索函数调用,然后假设在整个目标文件中未被调用的函数调用是你的入口点。看起来有点受虐狂,但再一次,手动加载和调用一个对象文件,而不是一个exe或加载一个DLL,在这种情况下,不需要知道入口点。下面是这两个函数我说的是:
/*
prologue:
push ebp ; 55
mov ebp esp ; 8B EC
functionCall:
call foo ; E8 &foo
*/
const unsigned char prologueBin[] = {0x55, 0x8B, 0xEC};
const unsigned char callOpcode = 0xE8;
inline bool isThisAfunction(unsigned char* pBin) {
return (pBin[0] == prologueBin[0] && pBin[1] == prologueBin[1] && pBin[2] == prologueBin[2]);
};
inline bool isThisCall(unsigned char* pBin) {
return *pBin == callOpcode;
};
isThisCall()可以打开了大量的误报,但因为你会用它来宰杀你的函数列表止跌回升通过isThisAfunction(),它是不可能消除一个并不真正被调用的函数。
基本上,我只推荐这个,如果你真的需要加载一块你完全不知道的东西并称之为函数。
您是否明确想要与'dlopen()'不同的东西,它在运行时加载共享库? –
你正在寻找的是所讨论的.o文件的文件格式,这取决于它们被编译的内容以及可能的编译时选项。 nm实用程序可能是您的朋友。 – JustJeff
此外,无论您是在编译“手动加载”代码,都需要有一个调用约定,与编译到正在加载的.o中的内容兼容。好事,这只是概念验证。 – JustJeff