Sunday, August 19, 2012

Dumping the memory of a process: easy recipe

Hi folks,

Though I promised an article dealing with adding free space to an existing section inside a PE, this little one will discuss with the dump of a process, eg. getting its memory content to save it in a file for a further analysis.

It can consist of several steps:
  • Listing every threads (quite important);
  • Suspending each thread so the memory will remain untouched while we dump the process;
  • Reading the memory;
  • Writing it into a file;
  • Resuming the suspended threads as if nothing happened.
Quite easy actually. A source code can to the whole stuff for you, using documented API and undocumented ones as well.

And I was meant to write a proof-of-concept for anyone that you may find here:

https://github.com/Ge0bidouille/ProcessMemoryDumper

I'm pretty sure that the source code is clear enough but feel free to drop a feedback if wanted!

Thanks go out to 0verclok for his feedbacks. :-)

Ge0

Saturday, August 4, 2012

Adding a section to your PE: the easy way

Hello again folks,

As I told you, I would release a little tool that let you to add a section to the pe binary of your choice, considering that it's compiled for a x86 target because my lib does not support the x64 one, a.k.a PE32+ or PE+.

Supposing you already know what the article deals with, I will even recall you a bit about what a section is: simply a region of code, which granularity is a memory page (4096 bytes). A section may contain whatever you want: code, data, read-only data... Therefore we point a first interest out: changing the access rights from section to section as well.

By adding a section to your binary, you may create a "code cave" and then put customised opcode / data... This is somewhat useful when you wish to patch a binary (cracking purposes? :P)

Now I suggest you to dive a bit into adding a fresh and new section to your binary...

First of all you have to choose a name and characteristics. This is the easy part.

But you have to think also about other useful information such the starting VirtualAddress, the size of raw data, etc. Since we told that the granularity of a section is actually a memory page, the VirtualAddress field's value must be 4096 bytes aligned and also must follow after the last section's VirtualAddress value plus its VirtualSize (very important in order not to overlap the whole).

E.G. suppose we have a binary composed of two sections: ".text" and ".data". Here is the mapping:

.text 0x00001000 : size 0x3000 bytes
.data 0x00004000 : size 0x2000 bytes

Because the .data section is 0x2000 bytes length, its relative memory addresses range will go from 0x00004000 to 0x00005FFF. So our new section will be located at 0x00006000.

Instead of doing some math (even though you like it, hackers!) you may get this value by actually copying the one of this the SizeOfImage field in OptionalHeader.

Your section must point to a physical space of data (actually this is not mandatory since some sections does not require some initialized data and just ask the loader to allocate a memory page...) that you'll have to create. So you should append some bytes to your binary. The number of bytes must be aligned to the FileAlignment field of OptionalHeader. With this new created bunch of bytes, you may provide further details to your section, such PointerToRawData, SizeOfRawData etc.

Secondly you have to make sure you have enough raw space to put the section header. Because in the memory page going from 0x00000000 to 0x00001000, you have both the MZ header and the PE header. And, at the end of the PE headers, you have every section headers; so if you miss space you would not be able to put your new section header... My algorithm unfortunately does not handle this case yet.

After having put it, you definitely have to edit two fields in the existing headers:
- the first one is obviously the SizeOfImage field that we talked about above; because your binary will grow after that;
- incrementing the NumberOfSection field located in the FileHeader since you have a fresh and new section.

And you're done! :-)

You may check the AddSection method's code that implements such algorithm.
VOID PortableExecutable::AddSection(PortableExecutable::SectionHeader& newSectionHeader) {
    DWORD dwRawSectionOffset = (DWORD)GetFileSize();

    /* Aligns dwRawSectionOffset to OptionalHeader.FileAlignment */
    dwRawSectionOffset += this->m_imageNtHeaders.OptionalHeader.FileAlignment - (dwRawSectionOffset % this->m_imageNtHeaders.OptionalHeader.FileAlignment);

    /* Does the whole header's length overflows OptionalHeader.SizeOfHeaders? */
    if(
        (sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) + (this->m_imageNtHeaders.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))
        > this->m_imageNtHeaders.OptionalHeader.SizeOfHeaders
        ) {

            /* If it's the case, add free space */
            AddFreeSpaceAfterHeaders( this->m_imageNtHeaders.OptionalHeader.FileAlignment );

            /* Adding 'FileAlignment' value to SizeOfHeaders fields then */
            this->m_imageNtHeaders.OptionalHeader.SizeOfHeaders += this->m_imageNtHeaders.OptionalHeader.FileAlignment;

    }

    newSectionHeader.SetPointerToRawData(dwRawSectionOffset);

    /* Adding the new section header */
    this->m_sectionHeaders.push_back(newSectionHeader);

    /* Incrementing the 'NumberOfSections' field */
    ++this->m_imageNtHeaders.FileHeader.NumberOfSections;

    /* Adding to SizeOfImage the SectionAlignment value */
    this->m_imageNtHeaders.OptionalHeader.SizeOfImage += this->m_imageNtHeaders.OptionalHeader.SectionAlignment;

    /* Rewriting the whole headers */
    m_stream.seekg(this->m_imageDosHeader.e_lfanew, std::ios::beg);
    m_stream.write((const char*)&this->m_imageNtHeaders, sizeof(IMAGE_NT_HEADERS));

    /* Rewriting the section headers then */
    std::vector<PortableExecutable::SectionHeader>::iterator it =
        this->m_sectionHeaders.begin();

    while(it != this->m_sectionHeaders.end()) {
        m_stream.write((const char*)&it->ImageSectionHeader(), sizeof(IMAGE_SECTION_HEADER));
        ++it;
    }

    /* Finally adding 'FileAlignment' bytes to the end of the file,
    which actually corresponds to the section's memory space! */
    m_stream.seekg(this->m_sectionHeaders.at( this->m_sectionHeaders.size()-1).GetPointerToRawData(), std::ios::beg);

    char* bytes = new char[this->m_imageNtHeaders.OptionalHeader.FileAlignment];
    ::memset(bytes, '\0', this->m_imageNtHeaders.OptionalHeader.FileAlignment);
    m_stream.write(bytes, this->m_imageNtHeaders.OptionalHeader.FileAlignment);
    delete[] bytes;
}


The method does not seem bogus on normal PE. But because I sometimes enjoy repeating myself, do not use it on corkami's files. ;-)

With these algorithms comes a basic-and-not-so-friendly toll called (warning!!!!) PeAddSection that asks your for a binary, section name and section characteristics so it will create a section into the binary if possible

#include <iostream>
#include <cstdlib>
#include <Windows.h>

#include "../PortableExecutable/PortableExecutable.h"

using namespace std;

DWORD ParseCharacteristics(LPCTSTR lpCharacteristics);

int main(int argc, char** argv) {
    DWORD dwCharacteristics;
    if(argc < 4) {
        printf("Usage: %s <pe file> <section name> <characteristics>\n", argv[0]);
        ExitProcess(-1);
    }
    
    try {
        dwCharacteristics = ParseCharacteristics(argv[3]);
        PortableExecutable pe(argv[1]);
        
        cout << "[*] Listing section headers." << endl;
        vector<PortableExecutable::SectionHeader>::iterator it = pe.SectionHeaders().begin();

        while(it != pe.SectionHeaders().end()) {
            cout << setw(9) << left << setfill(' ') << it->GetName() <<  " ";
            cout << "0x" << setw(8) << hex << setfill('0') << right << it->GetVirtualAddress() << endl;
            ++it;
        }
        cout << "[*] Adding " << argv[2] << " section... with 0x" << ParseCharacteristics(argv[3]) << " in characteristics..." << endl;
        pe.AddSection(argv[2],  dwCharacteristics);
        cout << "[+] Normally done, check your pe!" << endl;
    } catch(const PortableExecutable::Exception& e) {
        cout << e.what() << endl;
        return -1;
    }

    return EXIT_SUCCESS;
}

DWORD ParseCharacteristics(LPCTSTR lpCharacteristics) {
    DWORD dwValue = 0;
    if(strlen(lpCharacteristics) == 10 && _strnicmp("0x", lpCharacteristics, 2) == 0) {
        sscanf_s(lpCharacteristics + 2, "%08X", &dwValue);
    }
    return dwValue;
}

All the stuff may be downloaded and followed here: https://github.com/Ge0bidouille/PeTools (I have created a new repository and modified the previous article). Help yourself!

That's all for the moment. Next time we will see an easy way to add free space to an existing section without creating a new one.

See you!

Ge0

Thursday, August 2, 2012

PE binaries modification, toward a library and a set of useful tools

Hi folks,

Sure it's been a while since I have not posted any blog entry. I was actually quite busy because of the studies and the like (mainly the studies I guess... Forced to learn Java, xml & other undesirable stuff).

A year after here is a post that deals with the portable executable file format. In fact I was quite pleased by R4ndom's blog: Modifying Binaries: The Never Ending Program. It reminded me an old work that was relinquished in the inners of my external hard drive (lol): a beginning of a library that let you deal with the portable executable file format.

Sure it might not handle corkami's tricky files, but it might help in the case of R4ndom's need: creating, for example, a cave of free space to add opcodes/data/anything you want.

The beginning of my library can be found here: https://github.com/Ge0bidouille/PeTools/, so help yourself as well. :-)

If you are quite interested in such a project, if you have already started your own one etc. feel free to get in touch with me so we could work together on it.

I unfortunately have a limited availability to both write a complete blog entry and release a relevant little tool that might be considered as a proof-of-concept of appending editable bytes into a pe binary. In addition of creating another blog entry, I will see how I could broadcast the tool (I actually cannot access my free.fr ftps since I am currently not located in France...).

Suggestions about all that stuff are obviously welcome.

Catch up later on this blog! In between stay in touch on twitter...

Ge0

Tuesday, July 26, 2011

Hot Patching a function: little example with Api Monitoring

Hi folks,

As mentionned in my last post, I wish I had made a blog entry concerning the hot patching. I didn't have much time for practicing it but I finally managed to prove this concept briefly.

I will provide three source codes which concern:
- a program that will inject a customized dll into a process of your choice;
- a dll that will hot patch the "GetModuleHandleA" function which is exported by the kernel32.dll module;
- a program to "hot patch".

Remembering the concept of "hot patching"

So, sometimes when you're diving into a reverse code engineering session, you might find instructions like "MOV EDI,EDI" as the first instruction of an exported routine from a module (eg. kernel32.dll, user32.dll...). This instruction looks useless but in reality it isn't. Moreover, if we look just a little above, we can see either five nop instructions or int3 ones. I don't especially think that they're runned by your processor.

These instructions aren't there by accident. They are there in order to allow us to "hot patch" the function / routine". Indeed, the "MOV edi, edi" measures 2 bytes and the sequence of nop / int3 instructions measures 5 bytes.

The concept of the hot patching consists in overwriting these seven bytes while running the process. The two bytes of "MOV edi, edi" will be overwritten by a short jump; this short jump then redirects the execution stream to the five nop / int3 instructions. And these 5 bytes are patched by a far jump / call, for example.

In our case, if we want to make API monitoring, we shall write a far call to our customized procedure that will print out "This function was called!" on the screen. This is a good start, isn't it?

But there's a little problem though. Suppose your routine, which role is to inform you of the attempt to call the hot patched function, finishes its execution, then you encounter the ret instruction. This instruction will obviously pop the saved instruction pointer of the stack.

And this saved instruction pointer will redirect our stream to... The short jump that we have written instead of "MOV edi, edi"! So we have to increase this saved EIP by two bytes. In fact that's easy:

void DLL_EXPORT foo() {
    asm("addl $2, 4(%ebp)");
    printf("GetModuleHandle was called!\n");
}

The saved EIP points to [ebp+4] because of the stack frame. Our function will be exported from a dll that we would have previously injected. And this function will have a prologue such as "PUSH EBP" and "MOV EBP, ESP"... And the "PUSH EBP" pushes a value onto the stack. It means that the stack looks like:

+--------------+ <---- ebp / esp
|  saved ebp   |
+--------------+ <---- ebp + 4
|  saved eip   |
+--------------+

The reason why I choose ebp instead of esp - and in fact it doesn't really matter in this case - is that by convention you can find the first argument of the routine at ebp+8, the second argument at ebp+12... When you've a stack frame. And at ebp+4 you've your saved EIP; you're not supposed to modify it, unless you're smashing the stack (buffer overflow).

So, by increasing the interesting value by two bytes, we will return after the short jump (the old "MOV edi, edi") and, after this instruction, there is the code of the routine.

What have we done? We have made a detour. Our "foo" function has been called before the GetModuleHandle function.

Now it's time to practice. First of all, here is the code of the dll to inject; it has both a header file and a C source file:

main.h
#ifndef __MAIN_H__
#define __MAIN_H__

#include <stdio.h>
#include <windows.h>

/*  To use this exported function of dll, include this header
 *  in your project.
 */

#ifdef BUILD_DLL
    #define DLL_EXPORT __declspec(dllexport)
#else
    #define DLL_EXPORT __declspec(dllimport)
#endif


#ifdef __cplusplus
extern "C"
{
#endif


void DLL_EXPORT foo();

#ifdef __cplusplus
}
#endif

#endif // __MAIN_H__


main.c
#include "main.h"


void DLL_EXPORT foo() {
    asm("addl $2, 4(%ebp)");
    printf("GetModuleHandle was called!\n");
}


void HotPatch(LPVOID lpOldFunction, LPVOID lpNewFunction)  {

    /* -5 because of the nop / int3 instructions */
    LPVOID lpNewOldFunctionPointer = lpOldFunction - 5;

    DWORD dwOldProtectionValue, dwNewProtectionValue;

    /* Calculating the call destination (-5 because of the call size) */
    LPVOID lpCallDestination = (LPVOID)(lpNewFunction - lpNewOldFunctionPointer - 5);

    VirtualProtect( (LPDWORD) lpNewOldFunctionPointer, 7, PAGE_EXECUTE_READWRITE, &dwOldProtectionValue);

    /* Writing the call */
    memcpy((LPVOID)lpNewOldFunctionPointer, "\xE8", sizeof(char));
    memcpy((LPVOID)(lpNewOldFunctionPointer + 1), &lpCallDestination, sizeof(LPVOID));

    /* Writing the jump */
    memcpy((LPVOID)(lpNewOldFunctionPointer + 5), "\xEB\xF9", 2 * sizeof(char));

    /* Set back the old protection */
    VirtualProtect((LPDWORD) lpNewOldFunctionPointer, 7, dwOldProtectionValue, &dwNewProtectionValue);
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    HINSTANCE hDll = LoadLibrary("kernel32.dll");


    LPVOID lpFunctionToHook = GetProcAddress(hDll, "GetModuleHandleA");

    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:


            // Rulz babe
            HotPatch(lpFunctionToHook, (LPVOID)foo);

            break;

        case DLL_PROCESS_DETACH:
            // detach from process
            break;

        case DLL_THREAD_ATTACH:
            // attach to thread
            break;

        case DLL_THREAD_DETACH:
            // detach from thread
            break;
    }
    return TRUE; // succesful
}

As you can see, when the DLL is loaded, it immediately "hot patches" the GetModuleHandle function in kernel32.dll - supposing that it's hot patchable and it is in my OS (Win7 x64).

We miss a dll injector and a little program. Here are the codes:

injector.c
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tlhelp32.h>

int InjectDllIntoProcess(DWORD dwPid, LPCTSTR szDll);
DWORD ProcessNameToPid(LPCTSTR lpszProcessName);

int main(int argc , char* argv[]) {

    if(argc < 3) {
        printf("Usage: %s <process> <dll>\n",argv[0]);
        exit(EXIT_FAILURE);
    }

    if(InjectDllIntoProcess(ProcessNameToPid(argv[1]),argv[2])) {
        printf("=== Dll successfully injected ===\n");
    }


    return EXIT_SUCCESS;
}


int InjectDllIntoProcess(DWORD dwPid, LPCTSTR szDll) {
    LPVOID                  lpReservedSpace         = NULL;
    DWORD                   dwSizeOfDllPath         = strlen(szDll) + 1;
    DWORD                   dwRet                   = 0;
    DWORD                   dwStatus                = 0;
    HANDLE                  hRemoteThread           = NULL;
    LPTHREAD_START_ROUTINE  lpThreadStartRoutine    = NULL;
    DWORD                   dwRemoteThreadId        = -1;
    printf("Opening the process... ");

    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
    if(hProcess != NULL) {

        printf("[OK]\nAllocating memory into the process...\n");
        LPVOID lpReservedSpace = VirtualAllocEx( hProcess, NULL, dwSizeOfDllPath, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        if(lpReservedSpace != NULL) {

            printf("[OK]\nWriting into the allocated memory space...\n");
            dwStatus = WriteProcessMemory(hProcess, lpReservedSpace, szDll, dwSizeOfDllPath , 0);
            if(dwStatus) {

                printf("[OK]\nCreating a remote thread into the process...\n");

                lpThreadStartRoutine = (LPTHREAD_START_ROUTINE)GetProcAddress(LoadLibrary("kernel32"),"LoadLibraryA");
                hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, lpThreadStartRoutine, lpReservedSpace, 0 , &dwRemoteThreadId );

                if(hRemoteThread != NULL) {
                    printf("[OK]\n");
                    WaitForSingleObject(hRemoteThread, INFINITE);
                    VirtualFreeEx(hProcess, lpReservedSpace, 0, MEM_DECOMMIT);

                    CloseHandle(hProcess);
                    CloseHandle(hRemoteThread);

                    dwRet = 1;
                }
            }
        }
    }

    return dwRet;
}

DWORD ProcessNameToPid(LPCTSTR lpszProcessName) {
    HANDLE      hSnapshot;
    PROCESSENTRY32  proc;
    DWORD       dwPid = -1;

    proc.dwSize = sizeof(PROCESSENTRY32);

    if((hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) != INVALID_HANDLE_VALUE) {

        if(Process32First(hSnapshot, &proc)) {
            if(!strcmp(lpszProcessName, proc.szExeFile)) {
                dwPid = proc.th32ProcessID;
            }

            while(dwPid == -1 && Process32Next(hSnapshot, &proc)) {
                if(!strcmp(lpszProcessName, proc.szExeFile)) {
                    dwPid = proc.th32ProcessID;
                }
            }
        }

        CloseHandle(hSnapshot);
    }

    return dwPid;
}



Finally, the target program.

hotpatchme.c
#include <stdio.h>
#include <windows.h>

int main(int argc, char **argv) {
    printf("Press enter once you've hooked.\n");
    getchar();
    GetModuleHandle(NULL);
}

Let's try the stuff.

C:\Users\Geoffrey\Mes documents\CPP>hotpatchme.exe
Press enter once you've hooked.


C:\Users\Geoffrey\Mes documents\CPP>

Relaunch it without pressing enter:

C:\Users\Geoffrey\Mes documents\CPP>hotpatchme.exe
Press enter once you've hooked.

In another prompt, launch the injector:

C:\Users\Geoffrey\Mes documents\CPP>dllinjector.exe
Usage: dllinjector.exe

C:\Users\Geoffrey\Mes documents\CPP>dllinjector.exe hotpatchme.exe hotpatch.dll
Opening the process... [OK]
Allocating memory into the process...
[OK]
Writing into the allocated memory space...
[OK]
Creating a remote thread into the process...
[OK]
=== Dll successfully injected ===

C:\Users\Geoffrey\Mes documents\CPP>

And press enter...

C:\Users\Geoffrey\Mes documents\CPP>hotpatchme.exe
Press enter once you've hooked.

GetModuleHandle was called!

C:\Users\Geoffrey\Mes documents\CPP>

It works! \o/

I hope you enjoyed the article. At the beginning I was attempting to write a more complete tool where you could have provided functions to monitor; this tool would have checked whether the dll was loaded or not - by browsing the loaded module list into the Process Environment Block - and other stuff but it takes a lot of time to make a clear and cleaned code. Nevertheless you figure out what I was talking about.

Thank you for having read this post. If you've any suggestion concerning the techniques or my poor English... Feel free to leave a comment!

Geo

Thanks go out to Gr3' for having fixed many english mistakes!

Friday, July 1, 2011

Listing "hot patchable" functions in a module

Hi folks!

Today, I will tell you about a little program that I've coded in order to list hot patchable functions in a module.

First and foremost, you must wonder what I mean by "hot patchable" and "module".

Well, the "hot patching", in Information Technology security, is simply a hooking method which consists in, according to the name, patching a function located in a module - a DLL in most cases.

An example of aim of the "hot patching" method is to hook a function, for debugging purposes.

But I've started a code in order to make hot patching for another purpose: API monitoring. I haven't implemented it yet, but I hope I will do it soon (maybe in a further article?).

By the way, how do we detect a hot patchable function?

Well, let's have a look at kernel32!SetHandleCount dissassembly:

7C80CD37 >/$ 8BFF           MOV EDI,EDI
7C80CD39  |. 55             PUSH EBP
7C80CD3A  |. 8BEC           MOV EBP,ESP
7C80CD3C  |. 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
7C80CD3F  |. 5D             POP EBP
7C80CD40  \. C2 0400        RETN 4

What should warn you is the first instruction: "MOV EDI, EDI". It does not look useful, but in reality it does! It's a kind of "nop instruction", coded by 2 bytes, that you can "rewrite" by whatever 2 bytes-coded instruction. For example, you can patch these 2 bytes by a short jump (EB XX). And fortunately for us, the 5 bytes above the "MOV EDI, EDI" instruction are:

7C80CD32     90             NOP
7C80CD33     90             NOP
7C80CD34     90             NOP
7C80CD35     90             NOP
7C80CD36     90             NOP

We can also patch these 5 bytes by a far jump (or a far call, as you want). Then we redirect the program stream to another region code (for example, an injected dll?).

I shall explain this technique in another article, eg. once I've implemented it.

Meanwhile, I suggest you this code which lists hot patchable functions from a dll:

/**
 * \file list_hot_patchable_functions.c
 * \brief little program that let you to list hotpatchable functions from a module
 * \author Geoffrey ROYER
 * \date 01/07/2011
 * \version 0.1
 */
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

/**
 * \fn void list_hotpatchable_functions(const char* module_name);
 * \brief simply dumps the list of hotpatchable functions from `module_name`
 * \param module_name (const char*) : path of the module name (mainly a dll file)
 * \example list_hotpatchable_functions("C:\\WINDOWS\\System32\\kernel32.dll");
 * \example list_hotpatchable_functions("C:\\WINDOWS\\System32\\user32.dll");
 * \return void
 */
void list_hotpatchable_functions(const char* module_name);

/**
 * \fn DWORD rva_to_offset(PIMAGE_SECTION_HEADER pBaseOfSectionHeaders, DWORD dwNumberOfSections, DWORD dwRva);
 * \brief calculate the equivalent offset of dwRva, basing on pBaseOfSectionHeaders feat dwNumberOfSections
 * \param pBaseOfSectionHeaders (PIMAGE_SECTION_HEADER) : pointer to the first section header of the PE
 * \param dwNumberOfSections (DWORD) : number of sections in the PE file
 * \param dwRva (DWORD) : the relative virtual address from which one you want the offset
 * \example no need :)
 * \return DWORD : offset of the specified relative virtual address
 */
DWORD rva_to_offset(PIMAGE_SECTION_HEADER pBaseOfSectionHeaders, DWORD dwNumberOfSections, DWORD dwRva);


int main(int argc, char **argv) {
    if(argc < 2) {
        printf("Usage: %s <module>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    list_hotpatchable_functions(argv[1]);

    return EXIT_SUCCESS;
}


void list_hotpatchable_functions(const char* module_name) {

    /* All utils variables */
    HANDLE                  hMapOfExe                   = INVALID_HANDLE_VALUE;
    HANDLE                  hExeHandle                  = INVALID_HANDLE_VALUE;
    LPVOID                  lpExeView                   = NULL;
    PIMAGE_DOS_HEADER       pImageDosHeader             = NULL;
    PIMAGE_NT_HEADERS       pImageNtHeaders             = NULL;
    PIMAGE_SECTION_HEADER   pImageSectionHeader         = NULL;
    PIMAGE_EXPORT_DIRECTORY pImageExportDirectory       = NULL;
    DWORD                   dwEatOffset                 = 0;
    DWORD                   dwEatVirtualAddress         = 0;
    LPDWORD                 tableNames                  = NULL;
    LPDWORD                 tableAddresses              = NULL;
    DWORD                   currentName                 = 0;
    DWORD                   currentRva                  = 0;
    DWORD                   offsetOfFunction            = 0;

    int i;
    int number_of_patchable_functions = 0;


    /* Opening the file */
    hExeHandle = CreateFile(
        module_name,
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        0,
        0
    );


    if(hExeHandle != INVALID_HANDLE_VALUE) {


        hMapOfExe = CreateFileMapping(
            hExeHandle,
            NULL,
            PAGE_READONLY,
            0,
            0,
            NULL
        );

        if(hMapOfExe != INVALID_HANDLE_VALUE) {

            /* Mapping the file */
            lpExeView = MapViewOfFile(
                hMapOfExe,
                FILE_MAP_READ,
                0,
                0,
                0
            );

            if(lpExeView != NULL) {

                /* Mapping with different pointers */
                pImageDosHeader         = (PIMAGE_DOS_HEADER) lpExeView;
                pImageNtHeaders         = (PIMAGE_NT_HEADERS) ((LPBYTE) pImageDosHeader + pImageDosHeader->e_lfanew);
                pImageSectionHeader     = (PIMAGE_SECTION_HEADER) ((LPBYTE) pImageNtHeaders + sizeof(IMAGE_NT_HEADERS));
                dwEatVirtualAddress     = pImageNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress;

                /* Retrieving the section of the export table address */
                dwEatOffset = rva_to_offset(
                    pImageSectionHeader,
                    pImageNtHeaders->FileHeader.NumberOfSections,
                    dwEatVirtualAddress
                );


                pImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY) ((LPBYTE) pImageDosHeader + dwEatOffset);

                DWORD dwOffsetTableNames        = rva_to_offset(
                    pImageSectionHeader,
                    pImageNtHeaders->FileHeader.NumberOfSections,
                    pImageExportDirectory->AddressOfNames
                );

                DWORD dwOffsetTableAddresses    = rva_to_offset(
                    pImageSectionHeader,
                    pImageNtHeaders->FileHeader.NumberOfSections,
                    pImageExportDirectory->AddressOfFunctions
                );


                tableNames      = (LPDWORD)( (LPBYTE)lpExeView + dwOffsetTableNames);
                tableAddresses  = (LPDWORD)( (LPBYTE)lpExeView + dwOffsetTableAddresses);


                printf("=== LIST OF PATCHABLE FUNCTIONS OF %s MODULE ===\n", module_name);


                for(i = 0; i < pImageExportDirectory->NumberOfNames; ++i) {

                    currentName = rva_to_offset(
                        pImageSectionHeader,
                        pImageNtHeaders->FileHeader.NumberOfSections,
                        *tableNames
                    );

                    currentRva = rva_to_offset(
                        pImageSectionHeader,
                        pImageNtHeaders->FileHeader.NumberOfSections,
                        *tableAddresses
                    );

                    offsetOfFunction = rva_to_offset(
                        pImageSectionHeader,
                        pImageNtHeaders->FileHeader.NumberOfSections,
                        currentRva
                    );

                    /* Hot patchable? */
                    if(*((PDWORD)((LPBYTE)lpExeView + currentRva - 5)) == 0x90909090 &&
                        *((PDWORD)((LPBYTE)lpExeView + currentRva - 2)) == 0xFF8B9090) {
                        ++number_of_patchable_functions;
                        printf(
                            "%s (0x%08X)\n",
                            (char*)(lpExeView + currentName),
                            (unsigned int)(pImageNtHeaders->OptionalHeader.ImageBase + *tableAddresses)
                        );
                    }


                    ++tableNames;
                    ++tableAddresses;

                }

                printf("-------------------------\nTotal: %d function(s)", number_of_patchable_functions);

                /* Freeing resource */
                UnmapViewOfFile(lpExeView);

            } else {
                printf("Error MapViewOfFile().\n");
            }

            CloseHandle(hMapOfExe);

        } else {
            printf("Error CreateFileMapping().\n");
        }

        CloseHandle(hExeHandle);

    } else {
        printf("Error CreateFile().\n");
    }

}

DWORD rva_to_offset(PIMAGE_SECTION_HEADER pBaseOfSectionHeaders, DWORD dwNumberOfSections, DWORD dwRva) {
    int i = 0;
    while(i < dwNumberOfSections) {
        if(pBaseOfSectionHeaders->VirtualAddress >= dwRva) {
            --i;
            --pBaseOfSectionHeaders;
            break;
        }
        ++pBaseOfSectionHeaders;
        ++i;
    }

    return pBaseOfSectionHeaders->PointerToRawData + (dwRva - pBaseOfSectionHeaders->VirtualAddress);
}


The code browses the export table address of a given module and read the 5 + 2 important bytes. If these bytes are composed of nops with a "mov edi, edi" instruction, then the function is considered as hot patchable.

If you have any suggest or any idea to improve the code (or the explanations, either), feel free to leave a comment.

For the moment, I don't have any stable depository, so I can't let you download any file. But I'm working on it...

Thank you for having read this blog entry!

Ge0