4

There was a question about this a year ago, but the answer doesn't explain how to do it in C/C++:

How to find start of .text section?

I'm not talking about module start address, which we can get using GetModuleHandle(module)

I'm talking about the start of text section of a DLL inside a process, so when i inject a process (using dll injection) i can get the starting address of a target DLL and patch part of its instructions, basically i know the offset of a instruction inside the DLL's file on disk, and i just want to find the start of text section and add to it that offset so i can patch it by injecting into the process that loaded it

and the offset of that part inside the PE file is different from disk, for example in a test program that i checked the offset in disk was 0x300 and on memory was 0x1000 (32 bit app)

so how can i do this that can work in both 32 bit and 64 bit apps?

0

3 Answers 3

4

There are lots of helper functions in dbghelp.h to fully parse the PE file

if you do not wish to use dbghelp.h almost all of these function has an Rtl Equivalent function in ntdll.dll which you can call dynamically (LoadLibrary, GetProcAddres)

For example, the function ImageNtHeader has an equivalent RtlImageNtHeader in ntdll.dll which you can use with GetProcAddress()

Below is a sample code that dump some pertinent details of all sections in a given module using dbghelp.h:

#include <windows.h>
#include <dbghelp.h>
#include <stdio.h>
#pragma comment(lib, "dbghelp.lib")
int main(void)
{
    HMODULE hMod = GetModuleHandleA("kernelbase.dll");
    if (hMod)
    {
        PIMAGE_NT_HEADERS64 NtHeader = ImageNtHeader(hMod);
        WORD NumSections = NtHeader->FileHeader.NumberOfSections;
        PIMAGE_SECTION_HEADER Section = IMAGE_FIRST_SECTION(NtHeader);
        for (WORD i = 0; i < NumSections; i++)
        {
            printf("%-8s\t%x\t%x\t%x\n", Section->Name, Section->VirtualAddress,
                   Section->PointerToRawData, Section->SizeOfRawData);
            Section++;
        }
    }
    return 0;
}

compile and linked and executed

cl /Zi /W4 /nologo /analyze /EHsc /Od %1 /link /release

TextSectAddr.exe
======================================
Name            VA      Raw     Size
======================================
.text           1000    400     102600
.rdata          104000  102a00  155e00
.data           25a000  258800  1600
.pdata          25f000  259e00  e800
.didat          26e000  268600  800
.rsrc           26f000  268e00  600
.reloc          270000  269400  22400
1

In order to get the text section of the desired dll, first you need its base address (DOS Header in other words) which leads you to its PE Header (using the e_lfanew field of IMAGE_DOS_HEADER).

At the PE Header (or in it's structured name IMAGE_NT_HEADERS) you'll find a field named FileHeader that contain information regarding the number of sections exist in the desired image.

to get to the first section (again it has a structured name IMAGE_SECTION_HEADER), you need to pass the DOS_HEADER, and NT_HEADERS by adding their size to the image's base address, and then you iterate through the sections checking it's Characteristics field for the values

IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE

which indicates for code/text section.

When you reach the header of the text section, you can use the field

VirtualAddress

to get the start address of the code section

Think of it as this struct

 ___________________________
|                           |
|      IMAGE_DOS_HEADER     |
|___________________________|
|                           |
|     IMAGE_NT_HEADERS      | <-- Contains FileHeader which has the number of sections exist in the dll
|___________________________|
|                           |
|   IMAGE_SECTION_HEADER    |
|___________________________|
|                           |
|   IMAGE_SECTION_HEADER    |
|___________________________|
|                           |
|   IMAGE_SECTION_HEADER    |
|___________________________|
|                           |
|   IMAGE_SECTION_HEADER    |
|___________________________|
|                           |
|   IMAGE_SECTION_HEADER    |
|___________________________|
1
  • Hi @stylo and welcome tom RE.SE. Thanks for contributing on our site. Just as a remark, the inquirer was rather specific about needing some kind of API or C/C++ function rather than merely the description of how to achieve the goal.
    – 0xC0000022L
    Commented Sep 15, 2019 at 20:50
0

Here is another way to get PE image sections using stylo's answer. The following C code uses fopen(), fread() and fseek() functions. So, this code can be use in any Unix-like systems.

int main(int argc, char* argv[])
{
    if (argc < 2)
        return;

    FILE* file = fopen(argv[1], "rb");
    if (file == NULL)
        return;

    IMAGE_DOS_HEADER dosHeader = { 0 };
    fread(&dosHeader, sizeof dosHeader, 1, file);
    fseek(file, dosHeader.e_lfanew, SEEK_SET);

    IMAGE_NT_HEADERS ntHeader = { 0 };
    fread(&ntHeader, sizeof ntHeader, 1, file);

    IMAGE_SECTION_HEADER secHeader = { 0 };

    for (int i = 0; i < ntHeader.FileHeader.NumberOfSections; i++)
    {
        fread(&secHeader, sizeof secHeader, 1, file);
        printf("%-8s\t%x\t%x\t%x\n",
               secHeader.Name,
               secHeader.VirtualAddress,
               secHeader.PointerToRawData,
               secHeader.SizeOfRawData);
    }

    return 0;
}

So, what does the code do?

  • fopen(3) opens the file in binary mode.
  • fread(3) reads IMAGE_DOS_HEADER structure.
  • fseek(3) sets file position indicator for the file stream to the starting of IMAGE_NT_HEADERS structure using dosHeader.e_lfanew value.
  • fread(3) reads IMAGE_NT_HEADERS structure.
  • Now reads all the section headers in a loop. Remember with fread the position indicator of the stream is advanced by the total amount of bytes read. So, no need to increment secHeader.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.