简体   繁体   中英

Can't convert my C++ PELoader from x86 to x64

I have this PELoader project which basically loads a PE into memory. and it's working fine with x86 PEs but when tried to make it work with x64s I got stuck.

What I've tried is:

  • I replaced some of the data types with the x64 equivalent such as IMAGE_NT_HEADERS* with IMAGE_NT_HEADERS64*
  • Even though it automatically uses the right one when you switch the architecture. but didn't make any difference.
  • I also replaced this casting (DWORD) with reinterpret_cast<DWORD_PTR> and the exception changed. I guess it was necessary but not enough.
  • I tried making data types bigger. and it solved some but I still have bad reallocation.

Update 2

I just found out that the problem is in the reallocation. (check the code)

I've fixed an Error before I discovered this and it was in the data type that stores the base address from the optional header.

it was stored in a DWORD but I've changed it to char* and problem solved.

so I think the Error is in the casting or some data types of some values.

Here is the relocation Code:

/** Handle relocations **/
    
    //this is how much we shifted the ImageBase
    DWORD_PTR delta_VA_reloc = (reinterpret_cast<DWORD_PTR>(ImageBase)) - p_NT_HDR->OptionalHeader.ImageBase;
    
    // if there is a relocation table, and we actually shitfted the ImageBase
    if (data_directory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0 && delta_VA_reloc != 0) {
        printf("\n[*] The allocated address is not the prefered address, started relocating\n");
        //calculate the relocation table address
        IMAGE_BASE_RELOCATION* p_reloc = (IMAGE_BASE_RELOCATION*)(ImageBase + data_directory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
        
        //once again, a null terminated array
        while (p_reloc->VirtualAddress != 0) {
            // how many relocations in this block
            // ie the total size, minus the size of the "header", divided by 2 (those are words, so 2 bytes for each)
            //std::cout << sizeof(WORD) << "\n"; sizeof word is 2
            DWORD size = (p_reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);

            // the first relocation element in the block, right after the header (using pointer arithmetic again)
            WORD* reloc = (WORD*)(p_reloc + 1);
            for (int i = 0; i < size; ++i) {
                
                //type is the first 4 bits of the relocation word
                int type = reloc[i] >> 12;

                // offset is the last 12 bits
                unsigned long long int offset = reloc[i] & 0x0fff;
                //printf("--------------- %#llx\n", offset);

                //this is the address we are going to change
                DWORD* change_addr = (DWORD*)(ImageBase + p_reloc->VirtualAddress + offset);

                // there is only one type used that needs to make a change
                // When you relocate you should look if the flag HIGHT_LOW is active for PE32 and DIR64 for PE32+
                switch (type) {
                case IMAGE_REL_BASED_HIGHLOW://for x86
                    *change_addr += delta_VA_reloc;
                    break;
                case IMAGE_REL_BASED_DIR64://for x64
                    *change_addr += delta_VA_reloc;
                    break;
                default:
                    break;
                }
            }

            // switch to the next relocation block, based on the size
            p_reloc = (IMAGE_BASE_RELOCATION*)((reinterpret_cast<DWORD_PTR>(p_reloc)) + p_reloc->SizeOfBlock);
        }
    }

I found the problem:

I don't know exactly but when using DWORD* in this line:

DWORD* change_addr = (DWORD*)(ImageBase + p_reloc->VirtualAddress + offset);

and I printed the chnage_addr, in x86 it prints the whole 6 bytes that represents the address.

but in x64 it only prints 4 bytes. I think in windows DWORD* is smaller in x64.

So the solution I found is using long data types

unsigned long long int* change_addr = (unsigned long long int*)(ImageBase + p_reloc->VirtualAddress + offset);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM