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

Wednesday, May 4, 2011

executing the DllMain function with a Code::Blocks DLL

Some months ago, I discovered with folks that a DLL developed with the Code::Blocks IDE does not execute its entry point when it is loaded.

When you create a DLL project under Code::Blocks, two files are generated:
  • main.h: file with macros, includes and other stuff;
  • main.cpp: code of the DllMain and exported functions.
Here are the source codes:

main.h
#ifndef __MAIN_H__
#define __MAIN_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
#endif


#ifdef __cplusplus
extern "C"
{
#endif

void DLL_EXPORT SomeFunction(const LPCSTR sometext);

#ifdef __cplusplus
}
#endif

#endif // __MAIN_H__

main.cpp
#include "main.h"

// a sample exported function
void DLL_EXPORT SomeFunction(const LPCSTR sometext)

{
    MessageBoxA(0, sometext, "DLL Message", MB_OK | MB_ICONINFORMATION);

}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)

{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:

            // attach to process
            // return FALSE to fail DLL load
            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

}

Though our DLL exports correctly the "SomeFunction" function, the DllMain is not called when the library is loaded (by linking or dynamic loading using the LoadLibrary() function).

The solution consists in adding the following directives which wrap the DllMain code:

#ifdef __cplusplus
extern "C"
{
#endif


#ifdef __cplusplus
}
#endif

Otherwise, just rename the main.cpp file into main.c! The problem is due to the fact that the DllMain function must not escape to the extern C rule; it's ok for the "SomeFunction" function, but DllMain has to be treated too!

Now you may try the following code:

main.cpp
#include "main.h"


// a sample exported function
void DLL_EXPORT SomeFunction(const LPCSTR sometext)

{
    MessageBoxA(0, sometext, "DLL Message", MB_OK | MB_ICONINFORMATION);

}

#ifdef __cplusplus
extern "C"
{
#endif
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)

{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:

            // attach to process
            // return FALSE to fail DLL load
            MessageBox(0, "Hello world!", "Message from DllMain", 0);

            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
}

#ifdef __cplusplus
}
#endif

This was just a little trick that I wish I could remember later.

Enjoy!

Ge0