获取作者here的操作码如下:
[bodo@bakawali testbed8]$ as testshell2.s -o testshell2.o
[bodo@bakawali testbed8]$ ld testshell2.o -o testshell2
[bodo@bakawali testbed8]$ objdump -d testshell2
然后他得到三个部分(或仅提到这三个部分):
< _start>
<起动机>
<安德>
我试图以相同的方式获取十六进制操作码但不能正确ld
。当然我可以用例如:
.o
和编译文件
gcc main.o -o prog -g
然而
时objdump --prefix-addresses --show-raw-insn -Srl prog
查看带注释和符号的完整代码,I have many additional sections there,例如:
的.init
.PLT
.text(是的,我知道,主要在这里)[这里很多部分:_start(),call_gmon_start(),__ do_global_dtors_aux(),frame_dummy(),main(),__ libc_csu_init(),__ libc_csu_fini() ,__ do_global_ctors_aux()]
调用.fini
我认为这些是gcc链接到运行时库引入的附加内容。我想我不需要这些所有部分从c代码调用操作码(作者只使用那3个部分)但是我的问题是我不知道我可能丢弃哪个,哪些是必要的。我想这样使用它:
#include <unistd.h>
char code[] = "\x31\xed\x49\x89\x...x00\x00";
int main(int argc, char **argv)
{
/*creating a function pointer*/
int (*func)();
func = (int (*)()) code;
(int)(*func)();
return 0;
}
所以我创造了这个:
#include <unistd.h>
/*
*
*/
int main() {
char *shell[2];
shell[0] = "/bin/sh";
shell[1] = NULL;
execve(shell[0], shell, NULL);
return 0;
}
我正如我所描述的那样进行了反汇编。我尝试使用.text main()中的操作码,这给了我分段错误,然后是.text main()+另外.text _start(),结果相同。
那么,从上面的部分中选择什么,或者如何仅生成与三个部分一样最小化的“prog”?
答案 0 :(得分:2)
字符代码[] =“\ x31 \ xed \ x49 \ x89 \ x ... x00 \ x00”;
这不起作用。
原因:代码肯定包含地址。主要是函数execve()的地址和字符串常量“/ bin / sh”的地址。
使用“code []”方法的可执行文件根本不包含字符串常量“/ bin / sh”,并且函数execve()的地址将不同(如果函数将链接到可执行文件中)全部)。
因此,对“execve()”函数的“call”指令将使用“code []”方法跳转到可执行文件中的任何位置。
关于可执行文件的一些理论 - 仅供参考:
可执行文件有两种可能性:
当使用相同的C代码时,静态链接的可执行文件比动态链接的可执行文件大得多因为所有C函数(例如“printf”,“execve”,...)必须捆绑到可执行文件。
当不使用任何这些库函数时,静态链接的可执行文件更简单,因此更容易理解。
静态链接的可执行行为
操作系统将静态链接的可执行文件加载到内存中(当使用execve()启动时)。可执行文件包含入口点地址。该地址存储在可执行文件的文件头中。你可以使用“objdump -h ...”看到它。
操作系统跳转到该地址,以便程序从该地址开始执行。地址通常是函数“_start”,但是当使用“ld”链接时,可以使用命令行选项更改。
“_start”处的代码将准备可执行文件(例如初始化变量,计算“argc”和“argv”的值,...)并调用“main()”函数。当“main()”返回时,“_ start”函数会将“main()”返回的值传递给“_exit()”函数。
动态链接的可执行行为
此类可执行文件包含两个附加部分。第一部分包含动态链接器的文件名(可能是“/lib/ld-linux.so.1”)。然后,操作系统将加载可执行文件和动态链接器,并跳转到动态链接器的入口点(而不是可执行文件的入口点)。
动态链接器将读取第二个附加部分:它包含有关可执行文件所需的动态库(例如“libc.so”)的信息。它将加载所有这些库并初始化许多变量。然后它调用所有库和可执行文件的初始化函数(“_init()”)。
请注意,操作系统和动态链接器都会忽略函数和节名称!入口点的地址取自文件头,“_ init()”函数的地址取自附加部分 - 函数的名称可能不同!
完成所有这些操作后,动态链接器将跳转到可执行文件的入口点(“_start”)。
关于“GOT”,“PLT”,......部分:
这些部分包含有关链接器加载动态库的地址的信息。 “PLT”部分包含包含跳转到动态库的包装代码。这意味着:“PLT”部分将包含一个函数“printf()”,它实际上什么都不做,只是跳转到“libc.so”中的“printf()”函数。这样做是因为直接从C代码调用动态库中的函数会使链接变得更加困难,因此C代码不会直接调用动态库中的函数。这种实现的另一个优点是“延迟链接”是可能的。
关于Windows的一些话
Windows只知道动态链接的可执行文件。 Windows XP甚至拒绝加载不需要DLL的可执行文件。 “动态链接器”已集成到操作系统中,而不是单独的文件。还有一个相当于“PLT”的部分。然而,许多编译器支持“直接”从C代码调用DLL代码而不首先调用PLT部分中的代码(理论上这在Linux下也是可能的)。不支持延迟链接。
答案 1 :(得分:1)
您应该阅读这篇文章:http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html。 它解释了创建非常小的程序所需的所有内容。