首页
论坛
课程
招聘
[原创]劫持正在运行进程的EIP注入代码的方法
2010-10-20 17:23 29409

[原创]劫持正在运行进程的EIP注入代码的方法

2010-10-20 17:23
29409
【标题】: 劫持正在运行进程的EIP注入代码的方法
【作者】: 火血狼(QQ:65845743)
【工具】: VC++2005, WINXP, WIN7
【声明】: 1.禁止用来做破坏;2.转载请告知作者.
-----------------------------------------------------------------------------
【灵感来源】
近日,在读<<Windows内核编程>>的时候,偶然发现,一个函数GetThreadContext,该函数可以使用户级的代码访问并操作指定线程的上下文:CONTEXT,通过这个CONTEXT里的一个字段EIP,我们可以得到CPU寄存器的当前值。当时就想,如果通过这个EIP允许修改,不就可以控制程序流程了吗?查了查资料,果然可以被另外用户态的进程修改,于是做了如下实验,实验目标:劫持EIP,执行自己代码,然后恢复EIP。

【第一步】修改另外进程的EIP寄存器
   SuspendThread(hThread);//这里先让线程挂起,避免EIP乱跑
   CONTEXT context;
   context.ContextFlags = CONTEXT_CONTROL;
   GetThreadContext(hThread, &context);
   DWORD dwEIP = context.Eip;
   context.ContextFlags = CONTEXT_CONTROL;
   //
   context.Eip = 0x000000; //这里随便设一个EIP值,导致目标进程崩溃
   SetThreadContext(hThread, &context);
   ResumeThread(hThread);

通过上面的代码实验,得出结论,EIP的设置是不受限制的。(其中hThread为目标进程的主线程句柄,至于如何得到,很多地方有例子,这里不再普及基础知识)

【第二步】构建合法的EIP值,引导目标进程EIP进入指定代码
在进行这一步的时候我遇到了以下几个问题:1.目标进程只能访问自身的虚拟内存地址;2.如何向内存中放入指定代码。
要解决第一个问题,就要用到
PVOID pCodeRemote = VirtualAllocEx(hProcess, NULL, (size_t)dwCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE));
这个代码将在目标进程的虚拟内存里申请一块儿大小为dwCodeSize的鲜活内存空间,并把内存起始指针返回。(并且页权限为可执行,可读写)
解决第二个问题,要用到汇编啦
写这样一个函数void __declspec(naked) __stdcall ASM_RemoteFunc(){
_asm{ int 3 }
}
然后把这个函数Copy到刚才的内存中,用到代码
WriteProcessMemory(hProcess, pCodeRemote, (PVOID)ASM_RemoteFunc, (size_t)dwCodeSize, NULL)
到这里,又有疑问了,怎么确定dwCodeSize呢?嗯,可以在函数末尾加个特殊值,然后查找到这个值,就可以确定函数的末尾地址了,嘿嘿,来试试
(naked修饰这里也不解释,请读者自行查资料)
void __declspec(naked) __stdcall ASM_RemoteFunc(){
_asm{ int 3; push 0x12345679 }
}

这样写搜索代码
void* find_ptr(void* mem, DWORD dwv)
{
void* ret_ptr;
__asm
{
  mov eax, mem
  jmp comp
diff: inc eax
comp: mov ebx, [eax]
  cmp ebx, dwv
  jnz diff
  mov ret_ptr, eax
}
return ret_ptr;
}
最后,函数大小可以通过下面代码来计算:
DWORD dwCodeStart = (DWORD)ASM_RemoteFunc; PVOID ptrCodeLocal = (PVOID)dwCodeStart; DWORD dwCodeEnd = (DWORD)find_ptr(ptrCodeLocal, PLACE_HOLDER_END) + 4; DWORD dwCodeSize = dwCodeEnd - dwCodeStart;
好了,第二部问题解决了,实验一下,果然,目标进程产生中断异常,说明执行了指定代码,但是最终程序还是会崩溃。如何能让程序不崩溃呢?

【第三步】寄存器和堆栈恢复
先分析一下程序为啥崩溃:因为我们改变EIP的时候,其代码有可能处于任何位置,执行完我们的代码后,并没有恢复原来的EIP指针,也没有保护好各个寄存器的值,目标进程会出现不可预计的现象。
如何恢复EIP呢,写过shellcode的人都知道,ret可以做到这一点,于是我们先push当前的EIP,然后,再结束的时候ret,就会返回到原来的地方执行EIP啦,于是这样写:
void __declspec(naked) __stdcall ASM_RemoteFunc(){
_asm{
      push 0x12345670
   ret
      push 0x12345679
}
}
呵呵,有人奇怪了,为啥用0x12345670而不用真正的EIP呢,因为这会儿我们无法得到,运行的时候才有。那怎么办呢?不用急,我们用找函数大小的方法找到0x12345670的地址,然后把目标进程的当前EIP,写入,不就行啦。
void * placeHolderEIP = find_ptr(ptrCodeLocal, 0x12345670);
memcpy((void *)placeHolderEIP, &dwEIP, 4);
运行,安静的通过,哈哈。
下面保护寄存器,并且调用一些有意思的代码:
#define PLACE_HOLDER_EIP 0x12345670
#define PLACE_HOLDER_ST1 0x12345671
#define PLACE_HOLDER_ST2 0x12345672
#define PLACE_HOLDER_FUN 0x12345678
#define PLACE_HOLDER_END 0x12345679
void __declspec(naked) __stdcall ASM_RemoteFunc(){
_asm{
      push PLACE_HOLDER_EIP;
      pushfd;
      pushad;
                  push MB_OK | MB_ICONINFORMATION
                  push PLACE_HOLDER_ST1;
                  push PLACE_HOLDER_ST2;
                  push NULL
      mov eax, PLACE_HOLDER_FUN;
      call eax;
      popad;
      popfd;
      ret;
      push PLACE_HOLDER_END
}
}

按照同样的内存查找的方法,把指定地方放入自己的值:
   HMODULE hModule = 0;
   if (!(hModule = LoadLibrary(_T("User32.dll")))) return false;
   DWORD funRemote = 0;
   if (!(funRemote = (DWORD)GetProcAddress(hModule, "MessageBoxA"))) return false;

   PVOID strRemote1 = NULL;
   if (!(strRemote1 = VirtualAllocEx(hProcess, NULL, (size_t)(strlen(strPam1) + 1), MEM_COMMIT, PAGE_READWRITE))) return false;
   PVOID strRemote2 = NULL;
   if (!(strRemote2 = VirtualAllocEx(hProcess, NULL, (size_t)(strlen(strPam2) + 1), MEM_COMMIT, PAGE_READWRITE))) return false;
   PVOID pCodeRemote = NULL;
   if (!(pCodeRemote = VirtualAllocEx(hProcess, NULL, (size_t)dwCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE))) return false;

   void * placeHolderEIP = find_ptr(ptrCodeLocal, PLACE_HOLDER_EIP);
   void * placeHolderST1 = find_ptr(ptrCodeLocal, PLACE_HOLDER_ST1);
   void * placeHolderST2 = find_ptr(ptrCodeLocal, PLACE_HOLDER_ST2);
   void * placeHolderFUN = find_ptr(ptrCodeLocal, PLACE_HOLDER_FUN);
   memcpy((void *)placeHolderEIP, &dwEIP, 4);
   memcpy((void *)placeHolderST1, &strRemote1, 4);
   memcpy((void *)placeHolderST2, &strRemote2, 4);
   memcpy((void *)placeHolderFUN, &funRemote, 4);

最后,把自己的函数复制到目标进程
  if (!WriteProcessMemory(hProcess, strRemote1, (LPCVOID)strPam1, strlen(strPam1), NULL)) return false;
  if (!WriteProcessMemory(hProcess, strRemote2, (LPCVOID)strPam2, strlen(strPam2), NULL)) return false;
  if (!WriteProcessMemory(hProcess, pCodeRemote, ptrCodeLocal, (size_t)dwCodeSize, NULL)) return false;
然后,ResumeThread(hThread),弹出messagebox,标题是strRemote1,内容为strRemote2指定的字符串值。
点ok后,目标进程安全无恙。大功告成!!

【结论】 EIP就是一切!!

[公告]请完善个人简历信息,好工作来找你!

收藏
点赞0
打赏
分享
最新回复 (35)
雪    币: 88
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
gezz 活跃值 2010-10-20 18:18
2
0
不错的方法。顶一个。
收藏了,谢谢。
雪    币: 73
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wil 活跃值 2010-10-20 19:25
3
0
不够精巧。应该获取目标进程的esp,代码放到堆栈里面,执行完之后eip恢复起始位置,什么痕迹都找不到的
雪    币: 100
活跃值: 活跃值 (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
dico 活跃值 2010-10-21 08:18
4
0
这种方法在病毒中早就有人实现了
雪    币: 139
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
lidyt 活跃值 2010-10-21 08:58
5
0
方法不错,主要是写入目标程序的shellcode不好弄
雪    币: 221
活跃值: 活跃值 (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
rock 活跃值 2010-10-21 11:18
6
0
写入的函数还要涉及到代码重定位
雪    币: 5972
活跃值: 活跃值 (106)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
傷遺忘 活跃值 2010-10-24 10:46
7
0
好帖子...学习了...谢谢分享
雪    币: 207
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Nod 活跃值 2010-10-24 20:05
8
0
劫持eip意义不大,不过也可以借鉴一些思路。
雪    币: 84
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kingpzh 活跃值 2010-10-24 20:49
9
0
学习了……谢谢
雪    币: 326
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
快雪时晴 活跃值 4 2010-10-24 21:34
10
0
远程 线程 进程 注入 劫持EIP
雪    币: 350
活跃值: 活跃值 (10)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
jgaoabc 活跃值 1 2010-10-24 23:04
11
0
方法很好,经过尝试,成功插入进程运行程序,但是360把这种方法认为是远程注入。

要在进程中插入任意EXE程序的实例可以参考暗组darkst 5.0的服务端,解决了重定位的问题。

写入目标程序的shellcode最好是采用动态生成输入表API函数地址,采用自定位代替重定位的方法。
雪    币: 793
活跃值: 活跃值 (10)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
zyr零零发 活跃值 1 2010-10-25 09:29
12
0
老技术翻新。。。。。
提供思路也不错。
雪    币: 1765
活跃值: 活跃值 (94)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
sisess 活跃值 1 2010-10-25 13:28
13
0
重定位之类的都是小问题了
WriteProcessMemory 这个搞好才是关键
不然杀软嗷嗷叫了
雪    币: 27
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:320 )
在线值:
发帖
回帖
粉丝
charme 活跃值 7 2010-10-26 18:55
14
0
这不就是  0x年前的 掏空进程嘛
雪    币: 78
活跃值: 活跃值 (12)
能力值: ( LV9,RANK:450 )
在线值:
发帖
回帖
粉丝
RegKiller 活跃值 10 2010-10-26 23:27
15
0
调试器中的指定新EIP位置是这功能不?
雪    币: 61
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
newtonlove 活跃值 2010-11-9 22:31
16
0
问一下
memcpy((void *)placeHolderEIP, &dwEIP, 4);
为什么我调试的时候错误:access violation
调试环境vc6.0+sp3
雪    币: 61
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
newtonlove 活跃值 2010-11-10 09:09
17
0
哪个好人能提示一下
雪    币: 478
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
flyingayi 活跃值 2010-11-10 09:41
18
0
关注。。。标记先。。
雪    币: 61
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
newtonlove 活跃值 2010-11-10 10:21
19
0
在线等待中.......
雪    币: 303
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bluecode 活跃值 2010-11-10 15:53
20
0
谢谢。好思路。
雪    币: 345
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
wzanthony 活跃值 2010-11-10 19:18
21
0
这方法倒是用过,不过有一点一直都不太放心,寄存器还有浮点寄存器,MMX寄存器等等。虽然一般来说自己写的代码不会改变这些寄存器,但是调用的API会不会改变它们真没有一个准确的说法。而且貌似没有什么好方法对它们进行还原。。。
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zchld 活跃值 2010-11-10 19:27
22
0
值得参考!!呵呵!
雪    币: 294
活跃值: 活跃值 (15)
能力值: ( LV15,RANK:280 )
在线值:
发帖
回帖
粉丝
ctaotao 活跃值 6 2010-11-11 13:16
23
0
通过这样的方法让目标进程执行代码,还不如直接CreateRemoteThread执行注入代码来的简单。更没有利用缓冲区溢出执行shellcode来的通用。
雪    币: 254
活跃值: 活跃值 (11)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
hacker一疒亻 活跃值 2010-11-11 14:48
24
0
针对正在运行的QQ程序写一个例子放上来吧
雪    币: 1162
活跃值: 活跃值 (47)
能力值: ( LV13,RANK:260 )
在线值:
发帖
回帖
粉丝
ycmint 活跃值 5 2010-11-21 21:30
25
0
好东西  提供一组思路。。但 确实 往进程或exe问文件写东西的时候 会被杀软 拼命的报告出来。。。
雪    币: 284
活跃值: 活跃值 (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
darkplayer 活跃值 2010-11-21 22:14
26
0
支持,虽然好像以前也看到过类似的帖子。
雪    币: 0
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
AQPOWER郑 活跃值 2010-11-21 23:45
27
0
虽然不太懂,可以看看,学一学
雪    币: 212
活跃值: 活跃值 (32)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hovey 活跃值 2010-11-22 00:05
28
0
p wh 这个方法有意思呀
雪    币: 59
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
ccnyou 活跃值 2010-11-22 06:45
29
0
感谢分享!LZ太强了!
雪    币: 139
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
lidyt 活跃值 2010-11-22 08:55
30
0
技术有点老了,杀软盯得很紧。。。
雪    币: 1659
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yodamaster 活跃值 2011-5-19 20:02
31
0
回复和原文都很精彩。
雪    币: 33
活跃值: 活跃值 (12)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
smokewind 活跃值 1 2011-5-19 20:16
32
0
学习下这个思路
雪    币: 53
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jacksona 活跃值 2011-6-2 15:20
33
0
是一个思路,不过我觉得同远程注入没太大的区别,只不过注程注入的API函数功能你自己实现了一下。
雪    币: 2158
活跃值: 活跃值 (203)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
sunsjw 活跃值 1 2011-6-3 10:11
34
0
虽然已经有人用过,但对于楼主的创新想像精神还是值得表扬的。
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
windwing 活跃值 2011-6-3 11:38
35
0
不错的方法,值得参考!!
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
huhuhehe 活跃值 2011-6-4 20:34
36
0
拜读了,很高明的方法
游客
登录 | 注册 方可回帖
返回