0
votes

I'm trying to get the RVA of specific functions in kernel32.dll so I can use the RVA as an offset from the base address of kernel32.dll in a specified process to get the VA of the functions I need to inject my dll. I already wasn't able to find LoadLibrary but I did find LoadLibraryExA and used that instead for my dll injector however I now can't find GetProcAddress which I was going to use to locate the VA of functions in my ThreadProc function. So if I can't find it that means I'm going to have to calculate and store the VA of every function I need and put it into a structure to pass to the LPVOID lpParam parameter of ThreadProc which isn't ideal.

Here's all related functions:

void* GetFileImage(char path[])
{
    HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);//Get a handle to the dll with read rights
    if(hFile == INVALID_HANDLE_VALUE){printf("Error getting file handle: %d", (int)GetLastError());return NULL;} //Check whether or not CreateFile succeeded

    HANDLE file_map = CreateFileMapping(hFile, NULL, PAGE_READONLY|SEC_IMAGE, 0, 0, "KernelMap"); //Create file map
    if(file_map == INVALID_HANDLE_VALUE){printf("Error mapping file: %d", (int)GetLastError());return NULL;} //Did it succeed

    LPVOID file_image = MapViewOfFile(file_map, FILE_MAP_READ, 0, 0, 0); //Map it into the virtual address space of my program
    if(file_image == 0){printf("Error getting mapped view: %d", (int)GetLastError());return NULL;} //Did it succeed

    return file_image; //return the base address of the image
}

DWORD RVAddress(char* image, const char* proc_name)
{
    DWORD address = 0xFFFFFFFF; 

    PIMAGE_DOS_HEADER pDos_hdr = (PIMAGE_DOS_HEADER)image; //Get dos header
    PIMAGE_NT_HEADERS pNt_hdr = (PIMAGE_NT_HEADERS)(image+pDos_hdr->e_lfanew); //Get PE header by using the offset in dos header + the base address of the file image
    IMAGE_OPTIONAL_HEADER opt_hdr = pNt_hdr->OptionalHeader; //Get the optional header
    IMAGE_DATA_DIRECTORY exp_entry = opt_hdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 
    PIMAGE_EXPORT_DIRECTORY pExp_dir = (PIMAGE_EXPORT_DIRECTORY)(image+exp_entry.VirtualAddress); //Get a pointer to the export directory 

    void** func_table = (void**)(image+pExp_dir->AddressOfFunctions); //Get an array of pointers to the functions
    WORD* ord_table = (WORD*)(image+pExp_dir->AddressOfNameOrdinals); //Get an array of ordinals
    BYTE** name_table = (BYTE**)(image+pExp_dir->AddressOfNames); //Get an array of function names

    for(int i=0;i<pExp_dir->NumberOfNames;i++) //until i is 1 less than how many names there are to iterate through elements
    {
        printf("%s ", (BYTE*)image+(DWORD)(intptr_t)name_table[i]); //print the name of each function iterated through, I went back and read through these names and didn't see GetProcAddress anywhere
        if(strcmp(proc_name, (const char*)(BYTE*)image+(DWORD)(intptr_t)name_table[i]) == 0) //Is it the function we're looking for?
        {
            address = (DWORD)(intptr_t)func_table[ord_table[i]];//If so convert the address of the function into a DWORD(hexadecimal)
            system("CLS"); //Clear the screen
            return address; //return the address of the function
        }
    }

    return (DWORD)0; //Other wise return 0
}

DWORD GetRemoteFunctionAddress(DWORD dwPid, char* kernel_path, char* function_name)
{
    HANDLE hSnapshot = INVALID_HANDLE_VALUE;
    MODULEENTRY32 me32;
    me32.dwSize = sizeof(MODULEENTRY32);

    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE|TH32CS_SNAPMODULE32, dwPid); //Get a snapshot of all the modules in the program(64 and 32 bit, 32 since kernel is 32)
    if(hSnapshot == INVALID_HANDLE_VALUE){printf("Snapshot failed");return 0;} //Snapshot not created

    if(!(Module32First(hSnapshot, &me32))) //Don't care about it because it will be the exe of the process
    {
        printf("Mod32First failed");
        return 0;
    }

    while(Module32Next(hSnapshot, &me32)) //Iterate through until...
    {
        if(me32.szModule == "kernel32.dll"||me32.szModule == "KERNEL32.DLL") //we find kernel32.dll
        {
            CloseHandle(hSnapshot);
            break;
        }
    }

    printf("\nBase address: 0x%08X\n", (DWORD)(intptr_t)me32.modBaseAddr); //Used this for CheatEngine

    DWORD RVA = (DWORD_PTR)RVAddress((char*)GetFileImage(kernel_path), function_name); //Get the relative virtual address of the function

    DWORD Load = (DWORD_PTR)me32.modBaseAddr+(DWORD_PTR)RVA; //Add the base address of kernel32.dll and the RVA of the function to get a DWORD representation of the address of the function in the remote process

    return Load; //return the address of the function in the remote process
}

Any help would be much appreciated.

1
now can't find GetProcAddress something in your code is wrong, cause GetProcAddress is definitely in kernel32.dll.. Possibly functions like this (getting address, injection, ...) already have been written by other people and packed in libraries so maybe it's less effort to find one and use it? - stijn
@stijn I'm fairly certain it isn't my program. One hunch I have is that maybe the function names got mangled because they were defined in a C++ compiler that would have made the symbols into special text data and not identified them just by their function name like a C compiler would. But I don't know. - Doe Joe
@stijn And if you see anything wrong with my code please feel free to point it out. - Doe Joe
GetProcAddress is a pure C function so no name mangling.. eg in powershell: dumpbin.exe /exports C:\Windows\System32\kernel32.dll | sls procadd outputs 588 24B 00022070 GetProcAddress. I don't have time to go through your code, but have you tried it yourself? Run it under the debugger, put a breakpoint in that loop and see what's in name_table. For one, stuff like (BYTE*)image+(DWORD)(intptr_t) looks weird. At least one of those casts is not needed. Not sure if that is the culprot though. - stijn
@stijn After looking at it in the memory dump it looks like it does contain GetProcAddress and many other functions it's apparently skipping over. I however have no idea why. Could it be I'm incorrectly doing pointer arithmetic when retrieving the name? - Doe Joe

1 Answers

0
votes

if(me32.szModule == "kernel32.dll"||me32.szModule == "KERNEL32.DLL")

You can't use == on char arrays, you have to use stricmp

Instead of all this you can just use:

GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "LoadLibraryA")

This will give you the absolute address at runtime