远程注入【注入分类】

 

注入分类

 

 

所谓注入就是将代码放进某个进程的地址空间并使它成为该进程的一部分;为了对某个进程进行操作,如获取某进程的数据,或者修改进程的私有数据结构等;则需将自己的代码放在目标进程的地址空间中运行,这时就需使用注入技术了;

 

代码编写为DLL格式,并注入到其它进程中称为DLL注入。另一种是利用API相关函数直接把代码写入要注入的进程。

进程是一个正在运行的程序,它拥有自己的地址空间,拥有自己的代码、数据和其他系统资源。一个进程包含了一个或者多个运行在此进程内的线程。

从定义上看出进程一定要有线程,线程是进程内存中的独立实体。

 

1. 利用注册表注入(myDLL)

 

 

 

在Windows NT/2000/XP/2003中,有一个注册表键值:

HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsHKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs

当某个进程加载User32.dll时,这里面列出的所有的DLL都将User32.dll利用LoadLibrary函数加载到该进程空间中。我们可以把自己的代码放在一个DLL中,并加入该键值,这样就可以注入到所有使用User32.dll的进程中了。当DLL以LoadLibrary的方式加载时,DllMain会被以DLL_PROCESS_ATTACH为原因调用,实际上我们也只需要关心DLL_PROCESS_ATTACH。

 

2. 利用Windows Hooks注入(mydll)

Windows系统给我们提供了一些挂钩函数(Hook),使得被挂钩的进程可以在自己处理接收到的消息之前,先执行我们的消息处理函数,而这个消息处理函数一般会放在DLL中,来让目标进程加载,这实际上已经达到了注入代码的效果。一般情况下,我们把挂钩函数和消息处理函数都放在dll中。如果是全局钩子,那么你的DLL将会在进程调用时载入到任意一个调用的进程的地址空间中,这样是相当浪费资源的。因此只对某一个指定的线程安装线程钩子。

 

3. 利用远程线程注入(myDLL)(自写装载器注入 myDLL)

1、取得远程进程的进程PID;//使用GetWindowThreadProcessId;

2、打开进程PID,并设定相应操作权限;//OpenProcess;

3、在远程进程空间中分配一段内存用来存放要注入的myDLL完整路径;//VirtualAllocEx;

4、将要注入的myDLL的路径写到刚才分配的远程进程空间;//WriteProcessMemory;

为什么要把我们要注入的myDLL的文件名写到远程进程的地址空间进行操作,《WINDOWS核心编程》中是这样描述的:“(要注入的DLL文件名)字符串是在调用进程的地址空间中。该字符串的地址已经被赋予新创建的远程线程,该线程将它传递给LoadLibraryA。但是,当LoadLibraryA取消对内存地址的引用时,DLL路径名字符串将不再存在,远程进程的线程就可能引发访问违规”;

5、从Kernel32.dll中取得LoadLibray的地址; // GetProcAddress(GetModuleHandle("Kernel32.dll"),"LoadLibraryW"); 

为什么不直接对LoadLibrary进行调用,《WINDOWS核心编程》中是这样描述的:“如果在对CreateRemoteThread的调用中使用一个对LoadLibrayA的直接引用,这将在你的模块的输入节中转换成LoadLibrayA的形实替换程序的地址。将形实替换程序的地址作为远程线程的起始地址来传递,会导致远程线程开始执行一些令人莫名其妙的东西。其结果很可能造成访问违规。”

6、调用CreateRemoteThread函数以从Kernel32.dll中取得的LoadLibraryA函数的地址为线程函数的地址,以我们要注入的DLL文件名为参数,创建远程线程;

7、等待远程线程结束(WaitForSingleObject),即等待LoadLibrary返回。

8、取回远程线程的结束码(GetExitCodeThtread),即LoadLibrary的返回值

9、释放分配的内存(VirtualFreeEx)。

10、关闭打开的句柄。(CloseHandle)



4. 利用特洛伊DLL进行注入:

这种方法的原理就是由自己写一个与原有进程调用的DLL具有相同接口函数的DLL,再用我们的DLL替换原有的DLL。在替换的过程中,由我们自己编写感兴趣的函数替换原有函数,而对其它不感兴趣的函数,则以函数转发的形式调用原有DLL中的函数。这里面有个前提,就是你在编写DLL时你必须知道原有DLL中的函数都有哪些,以免导至其它进程调用DLL时找不到相应的API函数,特别是在替换系统DLL文件时更要小心。

5. 利用远程线程直接注入:(无DLL)

 

在第三中方法中,我们启动远程线程时,线程函数是我们从Kernel32.dll中取得的LoadLibrary函数的地址为线程函数的地址,其实我们可以直接将线程函数体和函数参数写入目标进程的地址空间,然后创建远程线程。
使用这个方法时,需要注意以下几个问题:
(▲) 远程线程函数体不得使用kernel32.dll,user32.dll以外的函数。因为这个两个模块在各个进程的相对地址是一样的,如果一定要使用其它函数,则必须将函数体写入目标进程空间。
(▲) 不能使用任何字符串常量,因为字符串常量是存放在PE文件里.data这个段里面的,函数里保存的只是相对地址。
(▲) 去掉编译器的/GZ编译选项,这个选项是用来Enable Stack Frame Run-Time Error Checking。当这个选项打开时,编译器会在每个函数中加入一些代码,用来检验ESP在函数体中是否被改变,但是这些检验函数的地址在不同PE文件中有可能是不一样的。
(▲) 不得使用增量链接(incremental linking)。增量链接是编译器为了减少链接时间做的处理,把函数体用一个JMP指令代替,这样就可以随意改变函数的内容,而不用修改CALL指令。
(▲) 不要在函数体内使用超过4kb的局部变量。局部变量是存放在栈中的,例如下面这个函数


 void Dummy(void) {
BYTE var[256];
var[0] = 0;
var[1] = 1;
var[255] = 255;
 }
 在分配局部变量空间时是这样的
 :00401000   push ebp
 :00401001   mov  ebp, esp
 :00401003   sub  esp, 00000100           ; change ESP as storage for
                                          ; local variables is needed
 :00401006   mov  byte ptr [esp], 00      ; var[0] = 0;
 :0040100A   mov  byte ptr [esp+01], 01   ; var[1] = 1;
 :0040100F   mov  byte ptr [esp+FF], FF   ; var[255] = 255;
 :00401017   mov  esp, ebp                ; restore stack pointer
 :00401019   pop  ebp
 :0040101A   ret


 但是当局部变量的大小超过4kb时,栈指针并不直接改版,而是调用另一个函数来分配内存,这个函数有可能在不同进程中的地址不一样。
(▲) 函数体内switch语句中的case不要超过3个,否则编译器会在PE文件中使用跳转表,而这个跳转表有可能在目标进程中并不存在。
 

 

 

转载于:https://www.cnblogs.com/okwary/articles/1358480.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值