有的时候,因为一些特殊目的,需要编译不带导入表甚至无PE头和初始化函数的shellcode。这里记录两种方法。
纯shellcode
当shellcode比较短的时候,可以通过函数实现+输出机器码的方式得到纯shellcode。方法是先正常写一个exe,将shellcode的函数全部写在里面,exe的main函数中输出这部分内容的机器码形成shellcode。这种方法比较麻烦一些,也有一些注意点:
首先是shellcode起始和末尾部分的界明和入口点的处理。比较简单的方法是定义两个标志函数,将shellcode部分的函数定义在其中,然后输出标志函数之间的机器码。
|
|
但是这种方法入口点就得手动处理了。所以有更高级的方法,在桩函数里call入口点。MalCode函数就是shellcode的入口点函数。输出shellcode时只需要输出MalCodeBegin函数和MalCodeEnd函数之间的机器码即可。
|
|
然后这样生成的shellcode还需要调整编译参数。
- C/C++ -> Optimization -> /O1, /Ob2, /Oi, /Os, /Oy-, /GL
- C/C++ -> Code Generation -> /MT, /GS-, /Gy
- Linker -> General -> /INCREMENTAL:NO
最后在main函数里dump输出即可
|
|
具有PE结构的无导入表DLL式shellcode
上面的方法确实是能输出纯粹的shellcode,但局限性很多。首先是编译起来很麻烦,要先实现到exe里再输出一个.bin再使用,而且若是代码比较复杂,多.c文件下就更难处理了。所以更多时候是希望能编译出具有动态链接库(DLL)PE结构但无导入表的shellcode。
首先正常创建一个动态链接库项目,然后配置Release项目属性
- C/C++ -> Code Generation -> /MT, /GS-, /Gy
- Linker -> General -> /INCREMENTAL:NO
- Linker -> Input -> /NODEFAULTLIB, 删除所有附加依赖项
- Linker -> Advance -> /ENTRY=DllMain
这样配置后,是无法使用所有API的,需要自己从PEB里通过getProcAddrByHash干出API函数地址使用。