Skip to content

Instantly share code, notes, and snippets.

@lab313ru
Created August 30, 2022 19:26
Show Gist options
  • Save lab313ru/34c52f0e448da1f86f5becce31f1abfb to your computer and use it in GitHub Desktop.
Save lab313ru/34c52f0e448da1f86f5becce31f1abfb to your computer and use it in GitHub Desktop.
TitanEngine unp64
#include <windows.h>
#include <stdio.h>
#include <psapi.h>
#include "inc\TitanEngine.h"
PROCESS_INFORMATION* fdProcessInfo;
LPVOID lpBaseOfImage;
char szDumpName[MAX_PATH] = "";
static void log(const char* format, ...)
{
va_list args;
va_start(args, format);
char msg[1024] = "";
vsprintf(msg, format, args);
puts(msg);
}
static void cbOep()
{
long long rip = GetContextData(UE_RIP);
log("> OEP 0x%llX reached!", rip);
log("> Dumping...");
DeleteFileA(szDumpName);
// Dump the process (notice that szDumpName need to be a full path)
if (!DumpProcess(fdProcessInfo->hProcess, lpBaseOfImage, szDumpName, rip))
{
log("> DumpProcess failed...");
StopDebug();
return;
}
log("> Dumping done!");
log("> Fixing imports...");
ULONG_PTR iatStart = 0;
ULONG_PTR iatSize = 0;
// Search for IAT (Search start is 'OEP' in Scylla)
ImporterAutoSearchIAT(fdProcessInfo->dwProcessId, szDumpName, rip, &iatStart, &iatSize);
if (!iatStart || !iatSize)
{
log("> IAT not found...");
StopDebug();
return;
}
log("> IAT Start: 0x%llX, IAT Size: 0x%llX", iatStart, iatSize);
char szSectionName[] = ".unp64";
// Auto fix the file (append a section & fix IAT)
if (!ImporterExportIATEx(szDumpName, szDumpName, szSectionName))
{
log("> ImporterExportIATEx failed...");
StopDebug();
return;
}
log("> Imports fixed!");
// Stop debugging
StopDebug();
}
static void cbNearOep()
{
log("> Near OEP!");
// Step using the trap flag
StepInto((void*)cbOep);
}
static void cbPeSpin()
{
// Set a hardware breakpoint at RSP with size 8 on read/write
SetHardwareBreakPoint(GetContextData(UE_RSP), UE_DR0, UE_HARDWARE_READWRITE, 8, (void*)cbNearOep);
}
static void cbEntry()
{
// Get RIP register
long long rip = GetContextData(UE_RIP);
log("> Entry point 0x%llX reached!", rip);
// Search for MPRESS pattern
unsigned char pattern[4] = { 0x5D, 0x5B, 0xC3, 0xE9 };
BYTE wildcard = 0;
long long found = Find((void*)rip, 0x1000, pattern, 4, &wildcard);
if (!found)
{ // Search for PESpin pattern
unsigned char pespin[4] = { 0xFF, 0x64, 0x24, 0xF8 };
long long found = Find((void*)rip, 0x1000, pespin, 4, &wildcard);
if (!found)
{
log("> MPRESS/PESpin pattern NOT found...");
StopDebug();
return;
}
log("> PESpin pattern found on 0x%llX!", found);
// Step over
StepOver((void*)cbPeSpin);
return;
}
// Set a simple INT3 breakpoint
SetBPX(found + 3, UE_BREAKPOINT, (void*)cbNearOep);
log("> MPRESS pattern found on 0x%llX!", found);
}
static void cbCreateProcess(CREATE_PROCESS_DEBUG_INFO* CreateProcessInfo)
{
// Get the loaded base
lpBaseOfImage = CreateProcessInfo->lpBaseOfImage;
log("> Process created on 0x%llX!", lpBaseOfImage);
}
static bool DevicePathToPath(const char* devicepath, char* path, size_t path_size)
{
if (!devicepath || !path)
return false;
char curDrive[3] = " :";
char curDevice[MAX_PATH] = "";
for (char drive = 'C'; drive <= 'Z'; drive++)
{
*curDrive = drive;
if (!QueryDosDeviceA(curDrive, curDevice, MAX_PATH))
continue;
size_t curDevice_len = strlen(curDevice);
if (!_strnicmp(devicepath, curDevice, curDevice_len))
// we match the device
{
if (strlen(devicepath) - curDevice_len >= path_size)
return false;
sprintf(path, "%s%s", curDrive, devicepath + curDevice_len);
return true;
}
}
return false;
}
static bool GetFileNameFromHandle(HANDLE hFile, char* szFileName)
{
if (!GetFileSize(hFile, 0))
return false;
HANDLE hFileMap = CreateFileMappingA(hFile, 0, PAGE_READONLY, 0, 1, 0);
if (!hFileMap)
return false;
void* pFileMap = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
if (!pFileMap)
{
CloseHandle(hFileMap);
return false;
}
char szMappedName[MAX_PATH] = "";
if (GetMappedFileNameA(GetCurrentProcess(), pFileMap, szMappedName, MAX_PATH))
{
DevicePathToPath(szMappedName, szFileName, MAX_PATH);
UnmapViewOfFile(pFileMap);
CloseHandle(hFileMap);
return true;
}
UnmapViewOfFile(pFileMap);
CloseHandle(hFileMap);
return false;
}
static void unpack(char* szFileName)
{
// Set an engine variable (hide console window of created process)
SetEngineVariable(UE_ENGINE_NO_CONSOLE_WINDOW, true);
// Get full file path
HANDLE hFile = CreateFileA(szFileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
log("> File \"%s\" doesn't exist...", szFileName);
return;
}
GetFileNameFromHandle(hFile, szDumpName);
CloseHandle(hFile);
log("> Unpack of file \"%s\" started...", szFileName);
FILE_STATUS_INFO inFileStatus = {};
if (IsPE32FileValidEx(szFileName, UE_DEPTH_DEEP, &inFileStatus) && inFileStatus.FileIs64Bit && !inFileStatus.FileIsDLL)
{
log("> 64-bit PE file detected!");
// Make name of dumped file
int len = strlen(szDumpName);
while (szDumpName[len] != '.' && len)
len--;
if (!len)
len = strlen(szDumpName);
strcpy(szDumpName + len, "_unp64.exe");
// Start the process
fdProcessInfo = (PROCESS_INFORMATION*)InitDebugEx(szFileName, 0, 0, (void*)cbEntry);
if (fdProcessInfo)
{
log("> InitDebug OK!");
// Set a custom handler
SetCustomHandler(UE_CH_CREATEPROCESS, (void*)cbCreateProcess);
// Start debug loop
DebugLoop();
}
else
log("> InitDebug failed...");
}
else
{
log("> Invalid/x86/DLL file...");
}
log("> Unpack ended");
}
int main(int argc, char* argv[])
{
puts("unp64 v0.1\n\nSupported packers:\nMPRESS v2.19\nPESpin v1.22 (Packer only)\n");
if (argc < 2)
puts("usage: unp64 [file.exe]");
else
unpack(argv[1]);
Sleep(2500);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment