9

通过.NET实现内存加载PE文件

 3 years ago
source link: https://3gstudent.github.io/3gstudent.github.io/%E9%80%9A%E8%BF%87.NET%E5%AE%9E%E7%8E%B0%E5%86%85%E5%AD%98%E5%8A%A0%E8%BD%BDPE%E6%96%87%E4%BB%B6/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

0x00 前言


在之前的文章《从内存加载.NET程序集(execute-assembly)的利用分析》《从内存加载.NET程序集(Assembly.Load)的利用分析》曾介绍了使用C Sharp从内存加载.NET程序集的方法,这次将要更近一步,介绍使用C Sharp从内存加载PE文件的方法

0x01 简介


本文将要介绍以下内容:

  • Casey Smith开源的PELoader.cs
  • 扩展PELoader.cs的方法
  • SharpPELoaderGenerater的实现细节

0x02 内存加载PE文件的实现原理


实现原理如下:

  1. 读取PE文件,按照PE格式进行解析
  2. 申请内存,ImageBase作为内存基地址,SizeOfImage作为长度
  3. 将PE文件头复制到内存中
  4. 解析Section的地址并将Section复制到内存中
  5. 基于重定位表修改内存
  6. 解析导入表,加载所需的Dll
  7. 跳转到入口地址AddressOfEntryPoint,执行PE文件

0x03 Casey Smith开源的PELoader.cs


目前可供参考的地址:

https://github.com/re4lity/subTee-gits-backups/blob/master/PELoader.cs

这个代码可以使用.NET 4.0或者更高版本下的csc.exe进行编译

编译命令如下:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /unsafe PELoader.cs

代码实现了在内存中加载64位的mimikatz.exe

PELoader.cs在字符串KatzCompressed存储经过编码后的mimikatz.exe

如果想要进行替换,可以参考我的代码,地址如下:

https://github.com/3gstudent/Homework-of-C-Sharp/blob/master/GzipandBase64.cs

执行后生成文件base64.txt,将其中的内容用来替换字符串KatzCompressed

0x04 扩展PELoader.cs的方法


1.增加支持的编译环境

PELoader.cs因为使用了.Add()导致不支持.Net3.5,可以对此进行替换使其支持.Net3.5

2.支持32位程序的加载

需要区分32位和64位程序PE结构的不同,重新计算偏移

扩展PELoader.cs的代码已上传至github,地址如下:

https://github.com/3gstudent/Homework-of-C-Sharp/blob/master/SharpMimikatz_x86.cs

https://github.com/3gstudent/Homework-of-C-Sharp/blob/master/SharpMimikatz_x64.cs

分别对应内存加载32位和64位mimikatz的代码

支持.Net3.5及更新版本

SharpMimikatz_x86.cs的编译命令如下:

C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe /unsafe /platform:x86 SharpMimikatz_x86.cs
or
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /unsafe /platform:x86 SharpMimikatz_x86.cs

SharpMimikatz_x64.cs的编译命令如下:

C:\Windows\Microsoft.NET\Framework64\v3.5\csc.exe /unsafe /platform:x64 SharpMimikatz_x64.cs
or
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /unsafe /platform:x64 SharpMimikatz_x64.cs

0x05 SharpPELoaderGenerater的实现细节


以Casey Smith开源的PELoader.cs为模板,尝试用c#实现自动生成加载PE文件的模板

这里以SharpMimikatz_x64.cs为例,代码可分成以下三部分:

  1. 前半部分调用代码
  2. exe文件经过压缩后的字符串
  3. 后半部分的调用代码

代码的生成方法如下:

1.前半部分调用代码

由于前半部分的调用代码存在多个转义字符,直接保存在string数组中比较麻烦,这里的思路是将前半部分的代码先经过压缩编码后再保存到string数组中,这样还能够大幅缩小代码长度(31kb压缩至6kb)

压缩前半部分代码可使用如下c#代码:

using System;
using System.IO;
using System.IO.Compression;

namespace GenerateCode
{
    class Program
    {
        static byte[] Compress(byte[] raw)
        {
            using (MemoryStream memory = new MemoryStream())
            {
                using (GZipStream gzip = new GZipStream(memory,
                CompressionMode.Compress, true))
                {
                    gzip.Write(raw, 0, raw.Length);
                }
                return memory.ToArray();
            }
        }
        static void Main(string[] args)
        {
            byte[] AsBytes = File.ReadAllBytes(@"SharpMimikatz_x86_part.cs");
            byte[] compress = Compress(AsBytes);
            String AsBase64String = Convert.ToBase64String(compress);

            StreamWriter sw = new StreamWriter(@"SharpMimikatz_x86_part.txt");
            sw.Write(AsBase64String);
            sw.Close();

            byte[] AsBytes2 = File.ReadAllBytes(@"SharpMimikatz_x64_part.cs");
            byte[] compress2 = Compress(AsBytes2);
            String AsBase64String2 = Convert.ToBase64String(compress2);

            StreamWriter sw2 = new StreamWriter(@"SharpMimikatz_x64_part.txt");
            sw2.Write(AsBase64String2);
            sw2.Close();
        }
    }
}

执行后生成文件SharpMimikatz_x86_part.txt和SharpMimikatz_x64_part.txt,内容为压缩编码后的前半部分调用代码

2.exe文件经过压缩后的字符串

可使用以下代码生成:

byte[] AsBytes = File.ReadAllBytes(@"mimikatz.exe");
byte[] compress = Compress(AsBytes);
string source = Convert.ToBase64String(compress);

3.后半部分的调用代码

这里需要使用转义字符

可使用以下代码进行定义:

string source3_x86 = "\";\r\n    }\r\n } ";

作为代码生成模板,还需要区分exe是32位还是64位,判断方法如下:

通过IMAGE_FILE_HEADER结构体中的Characteristics字段,如果存在属性IMAGE_FILE_32BIT_MACHINE,那么该exe文件为32位

完整代码已上传至github,地址如下:

https://github.com/3gstudent/Homework-of-C-Sharp/blob/master/SharpPELoaderGenerater.cs

用法实例:

SharpPELoaderGenerater.exe test.exe

如果test.exe为32位的程序,将会生成文件SharpPELoader_x86.cs

编译方法:

C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe /unsafe /platform:x86 SharpPELoader_x86.cs
or
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /unsafe /platform:x86 SharpPELoader_x86.cs

如果test.exe为64位的程序,将会生成文件SharpPELoader_x64.cs

编译方法:

C:\Windows\Microsoft.NET\Framework64\v3.5\csc.exe /unsafe /platform:x64 SharpPELoader_x64.cs
or
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /unsafe /platform:x64 SharpPELoader_x64.cs

使用c++编写test.exe时需要注意手动加上需要调用的dll

实例代码如下:

#include "stdafx.h"
#include <windows.h>
#pragma comment(lib,"User32.lib")
int main(int argc, char *argv[])
{
	LoadLibrary(L"User32.dll");
	MessageBox(NULL, NULL, NULL, MB_OK);
	return 0;
}

0x06 小结


本文介绍了通过.NET实现内存加载PE文件的方法,以Casey Smith开源的PELoader.cs为模板,编写代码生成工具SharpPELoaderGenerate,分享代码开发需要注意的细节


LEAVE A REPLY


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK