Jump to content
Tuts 4 You

[SDK Example] x64 MPRESS/PESpin Unpacker


Recommended Posts


Hello everyone,

Here is a small SDK example for TitanEngine Community Edition. It covers far from all features, but enough to get you started.

This is the code: 

#include <windows.h>#include <stdio.h>#include <psapi.h>#include "TitanEngine\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;}
Example output:
unp64 v0.1Supported packers:MPRESS v2.19PESpin v1.22 (Packer only)> Unpack of file "mpress.exe" started...> 64-bit PE file detected!> InitDebug OK!> Process created on 0x140000000!> Entry point 0x14000F0F3 reached!> MPRESS pattern found on 0x14000FBD7!> Near OEP!> OEP 0x140005DC8 reached!> Dumping...> Dumping done!> Fixing imports...> IAT Start: 0x14000F048, IAT Size: 0x38> Imports fixed!> Unpack ended
Project files + Binaries attached.


Mr. eXoDia


Edited by Mr. eXoDia (see edit history)
  • Like 7
  • Thanks 1
Link to post
  • 1 month later...
  • 4 weeks later...

Hmm.. Does anything like this exist for 32 bit files?


The file I need to unpack is a 32 bit .exe packed with Mpress v2.17..

Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Create New...