使用 .NET 文件时 RunPE 不起作用
RunPE doesen't work when using a .NET file
免责声明:我仅将 RunPE 用于教育目的并在我自己的计算机上使用。
首先:大家好!
我正在尝试使用具有 .NET 依赖项(用 C# 语言编写)的文件来使用 RunPE。
首先,当使用本机 c++ 文件而不是 .NET 文件时,代码没有显示任何问题:
但是每当我尝试使用用 C# 编码或具有 .NET 依赖项的文件时,就会发生这种情况:
我做了一些挖掘,在另一个 Whosebug 线程上,我发现了这个 (RunPE c++ only works with 32 console):
1.gui applications only run on the memory of other GUI applications as well GUI application only run on memory of other cui application.
because cui application on new windows run by conhost and not direct.
2.for run .net application from memory in c++ you must repair import table and other thing.to run .net application from .net is simply with
答案本身不是很好,但它揭示了问题可能是什么:导入 table 需要重建,我们需要 运行 另一个 GUI 应用程序中的应用程序,而不是像我这样的控制台。
我不知道如何在 C++ 中重建导入 table,我也不知道另一个“东西”是什么。
有人有一些有用的文档或知道如何在 C++ 中重建导入 table 吗?
这里我留下我的代码以供进一步分析:
#include <fstream>
#include <Windows.h>
#define STUB_SIZE 114176
bool LoadDataIntoProcess(void* Image)
{
DWORD DataRead = 0;
DWORD DataWritten = 0;
PIMAGE_DOS_HEADER pIDH = (PIMAGE_DOS_HEADER)Image;
if (pIDH->e_magic != IMAGE_DOS_SIGNATURE)
{
std::cout << "Il file non è in un formato eseguibile.\n";
return 0;
}
PIMAGE_NT_HEADERS pINH = (PIMAGE_NT_HEADERS)((DWORD)Image + pIDH->e_lfanew);
if (pINH->Signature != IMAGE_NT_SIGNATURE)
{
std::cout << "Il file non è in un formato eseguibile.\n";
return 0;
}
PIMAGE_SECTION_HEADER pISH = IMAGE_FIRST_SECTION(pINH);
STARTUPINFOA si;
PROCESS_INFORMATION pi;
DWORD ImageBase;
void* pImageBase;
char CurrentPath[1024];
std::cout << "Prendo nome del modulo...\n";
GetModuleFileNameA(NULL, CurrentPath, 1024);
ZeroMemory(&pi, sizeof(pi));
ZeroMemory(&si, sizeof(si));
std::cout << "Creo processo...\n";
if (CreateProcessA(CurrentPath, 0, 0, 0, FALSE, CREATE_SUSPENDED, 0, 0, &si, &pi))
{
LPCONTEXT ctx = (LPCONTEXT)VirtualAlloc(NULL, sizeof(ctx), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
ctx->ContextFlags = CONTEXT_FULL;
std::cout << "Prendo contesto del thread...\n";
if (GetThreadContext(pi.hThread, ctx))
{
std::cout << "Inizializzo puntatore alla base dell'eseguibile...\n";
bool Read = ReadProcessMemory(pi.hProcess, (LPCVOID)(ctx->Ebx + 8), (LPVOID)&ImageBase, 4, &DataRead);
if (!Read)
{
std::cout << "Errore durante la lettura della memoria del processo.\n";
return 0;
}
else
{
std::cout << "Letti " << DataRead << " bytes dal processo.\n";
DataRead = 0;
}
pImageBase = VirtualAllocEx(pi.hProcess, (LPVOID)pINH->OptionalHeader.ImageBase, pINH->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
bool Write = WriteProcessMemory(pi.hProcess, pImageBase, Image, pINH->OptionalHeader.SizeOfHeaders, &DataWritten);
if (!Write)
{
std::cout << "Errore: Impossibile scrivere all'interno del processo.\n";
return 0;
}
else
{
std::cout << "Scritti " << DataWritten << " all'interno del processo.\n";
DataWritten = 0;
}
std::cout << "SizeOfHeaders: " << pINH->OptionalHeader.SizeOfHeaders << ".\n";
for (int i = 0; i < pINH->FileHeader.NumberOfSections; i++)
{
std::cout << "Sezione " << i + 1 << " di " << pINH->FileHeader.NumberOfSections << ".\n";
Write = WriteProcessMemory(pi.hProcess, (LPVOID)((DWORD)pImageBase + pISH[i].VirtualAddress), (LPVOID)((DWORD)Image + pISH[i].PointerToRawData), pISH[i].SizeOfRawData, 0);
if (!Write)
{
std::cout << "Errore: Impossibile scrivere all'interno del processo.\n";
return 0;
}
std::cout << "\tVA: 0x" << pISH[i].VirtualAddress << "\n\tPointerToRawData: 0x" << pISH[i].PointerToRawData << "\n\t SizeOfRawData: " << pISH[i].SizeOfRawData << ".\n";
}
std::cout << "Scrivo ImageBase dentro al processo...\n";
Write = WriteProcessMemory(pi.hProcess, (LPVOID)(ctx->Ebx + 8), (LPVOID)&pINH->OptionalHeader.ImageBase, 4, 0);
if (!Write)
{
std::cout << "Errore: Impossibile scrivere all'interno del processo.\n";
return 0;
}
std::cout << "Imposto entrypoint...\n";
ctx->Eax = (DWORD)pImageBase + pINH->OptionalHeader.AddressOfEntryPoint;
std::cout << "Riassumo il thread...\n";
bool STC = SetThreadContext(pi.hThread, ctx);
if (!STC)
{
std::cout << "Errore: Impossibile impostare il context del processo.\n";
return 0;
}
ResumeThread(pi.hThread);
std::cout << "Avvio completato.\n";
return 1;
}
else
{
std::cout << "Errore: Impossibile prendere contesto del thread.\n";
return 0;
}
}
else
{
std::cout << "Errore: Impossibile creare il processo.\n";
return 0;
}
}```
编译器设置 /cls 修复了所有问题,这在尝试使用 .NET 二进制文件运行 PE 时很重要。
免责声明:我仅将 RunPE 用于教育目的并在我自己的计算机上使用。
首先:大家好! 我正在尝试使用具有 .NET 依赖项(用 C# 语言编写)的文件来使用 RunPE。
首先,当使用本机 c++ 文件而不是 .NET 文件时,代码没有显示任何问题:
但是每当我尝试使用用 C# 编码或具有 .NET 依赖项的文件时,就会发生这种情况:
我做了一些挖掘,在另一个 Whosebug 线程上,我发现了这个 (RunPE c++ only works with 32 console):
1.gui applications only run on the memory of other GUI applications as well GUI application only run on memory of other cui application. because cui application on new windows run by conhost and not direct.
2.for run .net application from memory in c++ you must repair import table and other thing.to run .net application from .net is simply with
答案本身不是很好,但它揭示了问题可能是什么:导入 table 需要重建,我们需要 运行 另一个 GUI 应用程序中的应用程序,而不是像我这样的控制台。
我不知道如何在 C++ 中重建导入 table,我也不知道另一个“东西”是什么。
有人有一些有用的文档或知道如何在 C++ 中重建导入 table 吗?
这里我留下我的代码以供进一步分析:
#include <fstream>
#include <Windows.h>
#define STUB_SIZE 114176
bool LoadDataIntoProcess(void* Image)
{
DWORD DataRead = 0;
DWORD DataWritten = 0;
PIMAGE_DOS_HEADER pIDH = (PIMAGE_DOS_HEADER)Image;
if (pIDH->e_magic != IMAGE_DOS_SIGNATURE)
{
std::cout << "Il file non è in un formato eseguibile.\n";
return 0;
}
PIMAGE_NT_HEADERS pINH = (PIMAGE_NT_HEADERS)((DWORD)Image + pIDH->e_lfanew);
if (pINH->Signature != IMAGE_NT_SIGNATURE)
{
std::cout << "Il file non è in un formato eseguibile.\n";
return 0;
}
PIMAGE_SECTION_HEADER pISH = IMAGE_FIRST_SECTION(pINH);
STARTUPINFOA si;
PROCESS_INFORMATION pi;
DWORD ImageBase;
void* pImageBase;
char CurrentPath[1024];
std::cout << "Prendo nome del modulo...\n";
GetModuleFileNameA(NULL, CurrentPath, 1024);
ZeroMemory(&pi, sizeof(pi));
ZeroMemory(&si, sizeof(si));
std::cout << "Creo processo...\n";
if (CreateProcessA(CurrentPath, 0, 0, 0, FALSE, CREATE_SUSPENDED, 0, 0, &si, &pi))
{
LPCONTEXT ctx = (LPCONTEXT)VirtualAlloc(NULL, sizeof(ctx), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
ctx->ContextFlags = CONTEXT_FULL;
std::cout << "Prendo contesto del thread...\n";
if (GetThreadContext(pi.hThread, ctx))
{
std::cout << "Inizializzo puntatore alla base dell'eseguibile...\n";
bool Read = ReadProcessMemory(pi.hProcess, (LPCVOID)(ctx->Ebx + 8), (LPVOID)&ImageBase, 4, &DataRead);
if (!Read)
{
std::cout << "Errore durante la lettura della memoria del processo.\n";
return 0;
}
else
{
std::cout << "Letti " << DataRead << " bytes dal processo.\n";
DataRead = 0;
}
pImageBase = VirtualAllocEx(pi.hProcess, (LPVOID)pINH->OptionalHeader.ImageBase, pINH->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
bool Write = WriteProcessMemory(pi.hProcess, pImageBase, Image, pINH->OptionalHeader.SizeOfHeaders, &DataWritten);
if (!Write)
{
std::cout << "Errore: Impossibile scrivere all'interno del processo.\n";
return 0;
}
else
{
std::cout << "Scritti " << DataWritten << " all'interno del processo.\n";
DataWritten = 0;
}
std::cout << "SizeOfHeaders: " << pINH->OptionalHeader.SizeOfHeaders << ".\n";
for (int i = 0; i < pINH->FileHeader.NumberOfSections; i++)
{
std::cout << "Sezione " << i + 1 << " di " << pINH->FileHeader.NumberOfSections << ".\n";
Write = WriteProcessMemory(pi.hProcess, (LPVOID)((DWORD)pImageBase + pISH[i].VirtualAddress), (LPVOID)((DWORD)Image + pISH[i].PointerToRawData), pISH[i].SizeOfRawData, 0);
if (!Write)
{
std::cout << "Errore: Impossibile scrivere all'interno del processo.\n";
return 0;
}
std::cout << "\tVA: 0x" << pISH[i].VirtualAddress << "\n\tPointerToRawData: 0x" << pISH[i].PointerToRawData << "\n\t SizeOfRawData: " << pISH[i].SizeOfRawData << ".\n";
}
std::cout << "Scrivo ImageBase dentro al processo...\n";
Write = WriteProcessMemory(pi.hProcess, (LPVOID)(ctx->Ebx + 8), (LPVOID)&pINH->OptionalHeader.ImageBase, 4, 0);
if (!Write)
{
std::cout << "Errore: Impossibile scrivere all'interno del processo.\n";
return 0;
}
std::cout << "Imposto entrypoint...\n";
ctx->Eax = (DWORD)pImageBase + pINH->OptionalHeader.AddressOfEntryPoint;
std::cout << "Riassumo il thread...\n";
bool STC = SetThreadContext(pi.hThread, ctx);
if (!STC)
{
std::cout << "Errore: Impossibile impostare il context del processo.\n";
return 0;
}
ResumeThread(pi.hThread);
std::cout << "Avvio completato.\n";
return 1;
}
else
{
std::cout << "Errore: Impossibile prendere contesto del thread.\n";
return 0;
}
}
else
{
std::cout << "Errore: Impossibile creare il processo.\n";
return 0;
}
}```
编译器设置 /cls 修复了所有问题,这在尝试使用 .NET 二进制文件运行 PE 时很重要。