《逆核》09-代码注入
代码注入
之前学习了DLL注入,实际上让进程执行我们自己的代码还有另一种方式,就是代码注入。
顾名思义,将代码注入进程,然后创建远程线程去执行。
和DLL注入的区别很明显:DLL注入是通过LoadLibrary自动执行DLL内的初始化函数从而实现执行我们的函数,而代码注入则是直接申请空间并写入函数机器码及对应传参,最后用CreateRemoteThread将函数首地址和传参首地址做参数来执行。
具体流程:
- 获取目标进程句柄
- 将参数打包为结构体
- 将结构体写入目标进程
- 将需要执行的函数写入目标进程
- 创建远程线程执行
按书上的直接写结果会崩溃,调试了一下发现因为有跳转表之类的东西,所以地址不对应
在项目-属性-链接器-增量链接-禁用后
项目-属性-C/C++-代码生成-安全检查-禁用
项目-属性-C/C++-优化-内联函数扩展-禁用
项目-属性-C/C++-常规-支持仅我的代码调试-禁用
以上几个禁用后,可以在debug配置下缩小代码规模和防止出现奇怪地址的跳转
同时似乎函数位置不一定和写代码的时候的位置一样,所以要看一下
然后是导入表的问题,如果是直接使用库函数,会直接跳转到导入表条目,所以不能在代码中直接使用库函数,必须取得后传地址过去。
实践C
1 |
|
其中targetCode是写入进程的函数,
uintptr_t funcSize = (uintptr_t)writeMemory - (uintptr_t)targetCode;的原因是我编译之后看了一下反编译结果,发现是这两个函数挨在一起,那么首地址相减就是大小了。
实践ASM
实际上,一般来说,代码注入都是注入汇编代码,因为汇编代码可以更方便地和寄存器,内存空间进行交互
如果要直接用汇编来完成操作,步骤为:
将执行的函数写为shellcode,然后创建远程线程执行,这里可以直接把数据和代码写在一起传递
1 | from keystone import * |
这段汇编总能出现一些奇怪的bug,要注意栈平衡和调用函数时栈最后一位为0,lea和mov什么时候传值什么时候传地址,以及x64下的基本调用方式。不管我写没写后面的pop,程序都会崩溃不知道为什么,但是messagebox确实弹出了。
1 | void injectCodeAsm(DWORD pid) { |