在分析样本时,我们会遇到各种骚操作,自我创建就是其中一种,简而言之就是将自身作为子进程运行,并且以子进程运行时会有不同的动作,如套娃创建子进程,执行shellcode等等。虽然这种手段并没有多么高明,但是在实际情况中常常会遇到,调试起来也比较麻烦,而且在真实环境中往往会更加复杂,所以掌握各种奇淫巧计是我等“杀人越货,行走江湖”必不可少的功夫,废话少说,开始开始实战!
根据特征找到main函数,我的是VS2013编译的,你的特征可能和我的不一样 !
调用CreateProcessW以挂起方式创建子进程
可以看到目前子进程处于挂起状态
使用GetThreadContext获取子进程的主线程的CONTEXT结构体
修改子进程的主线程的CONTEXT结构体中的EIP的值为ChildProc,然后调用SetThreadContext进行设置
恢复子进程的主线程
调用WaitForSingleObject进入等待状态直到子进程运行完毕
点击确定后子程序结束运行并返回
假如我们想要调试ChildProc函数,有很多方法可以用,比如在OD中直接将EIP的值设置为ChildProc的起始地址,或者将PE文件的EntryPoint修改为ChildProc的起始地址,但是很多时候,以上两种方法并不管用,除此之外还有一种方法,就是使用OD的实时调试模式。
1、设置OD为实时调试模式
2、将虚拟地址00171000(ChildProc函数在内存的位置)转换为文件偏移地址(在文件中的位置),
得到的结果为400
使用十六进制编辑器将对应的位置修改为CC并保存,如下图:
修改前
修改并保存
再次使用OD调试,在ResumeThread处下断点,单步步过
因为OD已经被设置为实时调试器,所以当有异常触发时,会被系统自动调用,并将其附加到对应的进程上,此时就可以开始调试了,最后别忘了把CC恢复为原代码(0x6A)(Crtl+E快捷键),然后就可以愉快的调试啦!!
自我创建技术在病毒木马等恶意软件中非常常见,经常借助该技术躲避安全软件查杀,为了方便演示,所以示例程序比较简单,但是掌握各种调试技巧,在遇到复杂的程序时才能游刃有余,手到擒来!
/
/
子进程要执行的代码
void ChildProc()
{
MessageBox(NULL, L
"This is a child process!"
, L
"DebugMe2"
, MB_OK);
ExitProcess(
0
);
}
/
/
主函数
void _tmain(
int
argc, TCHAR
*
argv[])
{
TCHAR szPath[MAX_PATH]
=
{
0
, };
STARTUPINFO si
=
{ sizeof(STARTUPINFO), };
PROCESS_INFORMATION pi
=
{
0
, };
CONTEXT ctx
=
{
0
, };
_tprintf(L
"This is a parent process!\n"
);
if
(!GetModuleFileName(NULL, szPath, sizeof(TCHAR)
*
MAX_PATH))
{
printf(
"GetModuleFileName() failed! [%d]\n"
, GetLastError());
return
;
}
/
/
创建子进程
if
(!CreateProcess(
szPath,
NULL,
NULL,
NULL,
FALSE,
CREATE_SUSPENDED,
NULL,
NULL,
&si,
&pi))
{
printf(
"CreateProcess() failed! [%d]\n"
, GetLastError());
return
;
}
/
/
修改EIP
ctx.ContextFlags
=
CONTEXT_FULL;
if
(!GetThreadContext(pi.hThread, &ctx))
{
printf(
"GetThreadContext() failed! [%d]\n"
, GetLastError());
return
;
}
ctx.Eip
=
(DWORD)ChildProc;
if
(!SetThreadContext(pi.hThread, &ctx))
{
printf(
"SetThreadContext() failed! [%d]\n"
, GetLastError());
return
;
}
/
/
恢复线程
if
(
-
1
=
=
ResumeThread(pi.hThread))
{
printf(
"ResumeThread() failed! [%d]\n"
, GetLastError());
return
;
}
/
/
等待返回
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
/
/
子进程要执行的代码
void ChildProc()
{
MessageBox(NULL, L
"This is a child process!"
, L
"DebugMe2"
, MB_OK);
ExitProcess(
0
);
}
/
/
主函数
void _tmain(
int
argc, TCHAR
*
argv[])
{
TCHAR szPath[MAX_PATH]
=
{
0
, };
STARTUPINFO si
=
{ sizeof(STARTUPINFO), };
PROCESS_INFORMATION pi
=
{
0
, };
CONTEXT ctx
=
{
0
, };
_tprintf(L
"This is a parent process!\n"
);
if
(!GetModuleFileName(NULL, szPath, sizeof(TCHAR)
*
MAX_PATH))
{
printf(
"GetModuleFileName() failed! [%d]\n"
, GetLastError());
return
;
}
/
/
创建子进程
if
(!CreateProcess(
szPath,
NULL,
NULL,
NULL,
FALSE,
CREATE_SUSPENDED,
NULL,
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2022-5-18 00:18
被寒江独钓_编辑
,原因: