有没有办法创建具有正确偏移量的剥离二进制文件?
Is there a way to create a a stripped binary with correct offsets?
我正在尝试将程序集文件转换为 C++,以用作用于另一个库的小型且易于插入的“蹦床”加载器。它在运行时被注入到另一个程序中,然后加载一个库,在其中运行一个函数,然后释放它。这只是为了避免需要对 WriteProccessMemory
进行多次冗长调用,并在需要时允许进行某些运行时检查。
最初,我用汇编编写代码,因为它让我可以高度控制文件的结构。我最终得到了一个 ~128 字节的文件,其结构如下:
<Relocation Header> // Table of function pointers filled in by the loading code
<Code>
<Static Data>
header 的 size/structure 在 compile-time 处已知,也允许计算入口点,因此加载它所需的代码很少。
问题是在我的汇编器 (NASM) 和编译器 (GCC) 之间共享 header 的结构是......困难的,因此重写。
我想出了这一系列命令 compile/link C++ 代码:
g++ -c -O3 -fpic Loader.cpp
g++ -O3 -shared -nostdlib Loader.o
运行 objcopy -O binary -j .text a.exe
然后给出一个只有大约 95 字节大小的二进制文件(我在汇编版本中手动插入了一些填充,以便在调试时清楚“部分”在哪里)。
只有一个问题(至少对于这个问题),变量偏移量没有被重新定位(很明显)。查看二进制文件,我可以看到像 mov rcx, QWORD PTR [rip+0x4fc9]
这样的行。显然,这在 95 字节的文件中是无效的。有没有办法(最好使用 GCC 或 Binutils 中的程序)我可以获得具有正确偏移量的剥离二进制文件?解决方案不必像 objcopy
这样的 post-process,它可以在构建过程的任何部分发生。
我真的很想避免文件中出现任何不需要的信息,这不一定有害,但这意味着超轻量级。该文件不需要直接运行(entry-point 不必为 0)。
另外需要说明的是,我并不是要求对所有指针进行简单的 addition/subtraction,GCC 生成的地址分布在内存中,它们应该与代码相冲突。
虽然不完整并且需要一些更改,但我想我现在已经想出了一个有效的解决方案。
我像以前一样编译,但是 link 使用稍微不同的命令:g++ -T lnkscrpt.txt -O3 -nostdlib Loader.o
(-shared
只是让 linker 抱怨缺少 DllMain)。
lnkscrpt.txt
是一个 ld
linker 脚本 (https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_5.html#SEC5),如下所示:
SECTIONS
{
. = 0x00;
.bss : { *(.bss) }
.text : { *(.text) }
.data : { *(.rdata) *(.data) }
/DISCARD/ : {*(*)}
}
这会保留我想要的顺序并丢弃任何其他默认部分。
最后我运行objcopy -O binary -j .* --set-section-flags .bss=alloc,load,contents a.exe
将剩余部分复制到平面二进制文件。 --set-section-flags
选项只是确保二进制文件包含分配给 .bss
部分的 space。
这会产生一个 128 字节的二进制文件,其布局方式与我的自定义程序集版本完全相同,使用正确的偏移量,并且不包含任何不需要的数据。
我正在尝试将程序集文件转换为 C++,以用作用于另一个库的小型且易于插入的“蹦床”加载器。它在运行时被注入到另一个程序中,然后加载一个库,在其中运行一个函数,然后释放它。这只是为了避免需要对 WriteProccessMemory
进行多次冗长调用,并在需要时允许进行某些运行时检查。
最初,我用汇编编写代码,因为它让我可以高度控制文件的结构。我最终得到了一个 ~128 字节的文件,其结构如下:
<Relocation Header> // Table of function pointers filled in by the loading code
<Code>
<Static Data>
header 的 size/structure 在 compile-time 处已知,也允许计算入口点,因此加载它所需的代码很少。
问题是在我的汇编器 (NASM) 和编译器 (GCC) 之间共享 header 的结构是......困难的,因此重写。
我想出了这一系列命令 compile/link C++ 代码:
g++ -c -O3 -fpic Loader.cpp
g++ -O3 -shared -nostdlib Loader.o
运行 objcopy -O binary -j .text a.exe
然后给出一个只有大约 95 字节大小的二进制文件(我在汇编版本中手动插入了一些填充,以便在调试时清楚“部分”在哪里)。
只有一个问题(至少对于这个问题),变量偏移量没有被重新定位(很明显)。查看二进制文件,我可以看到像 mov rcx, QWORD PTR [rip+0x4fc9]
这样的行。显然,这在 95 字节的文件中是无效的。有没有办法(最好使用 GCC 或 Binutils 中的程序)我可以获得具有正确偏移量的剥离二进制文件?解决方案不必像 objcopy
这样的 post-process,它可以在构建过程的任何部分发生。
我真的很想避免文件中出现任何不需要的信息,这不一定有害,但这意味着超轻量级。该文件不需要直接运行(entry-point 不必为 0)。
另外需要说明的是,我并不是要求对所有指针进行简单的 addition/subtraction,GCC 生成的地址分布在内存中,它们应该与代码相冲突。
虽然不完整并且需要一些更改,但我想我现在已经想出了一个有效的解决方案。
我像以前一样编译,但是 link 使用稍微不同的命令:g++ -T lnkscrpt.txt -O3 -nostdlib Loader.o
(-shared
只是让 linker 抱怨缺少 DllMain)。
lnkscrpt.txt
是一个 ld
linker 脚本 (https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_5.html#SEC5),如下所示:
SECTIONS
{
. = 0x00;
.bss : { *(.bss) }
.text : { *(.text) }
.data : { *(.rdata) *(.data) }
/DISCARD/ : {*(*)}
}
这会保留我想要的顺序并丢弃任何其他默认部分。
最后我运行objcopy -O binary -j .* --set-section-flags .bss=alloc,load,contents a.exe
将剩余部分复制到平面二进制文件。 --set-section-flags
选项只是确保二进制文件包含分配给 .bss
部分的 space。
这会产生一个 128 字节的二进制文件,其布局方式与我的自定义程序集版本完全相同,使用正确的偏移量,并且不包含任何不需要的数据。