https://git.reactos.org/?p=reactos.git;a=commitdiff;h=9e0a3cdf6cf61c66cae05f0538c38b1d644ca7d6

commit 9e0a3cdf6cf61c66cae05f0538c38b1d644ca7d6
Author:     Hermès Bélusca-Maïto <[email protected]>
AuthorDate: Sun Apr 11 02:30:15 2021 +0200
Commit:     Hermès Bélusca-Maïto <[email protected]>
CommitDate: Sun May 9 01:39:21 2021 +0200

    [PEFIXUP] Add support for overriding the attributes of specific PE 
sections. (#3598)
    
    Use a syntax identical to the one from the EDITBIN tool:
    --section:name[=newname][,[[!]{CDEIKOMPRSUW}][A{1248PTSX}]]
    
    
https://docs.microsoft.com/en-us/cpp/build/reference/section-editbin?view=msvc-160
---
 sdk/tools/pefixup.c | 313 +++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 271 insertions(+), 42 deletions(-)

diff --git a/sdk/tools/pefixup.c b/sdk/tools/pefixup.c
index 22c0f6eb6e4..4d064b8574d 100644
--- a/sdk/tools/pefixup.c
+++ b/sdk/tools/pefixup.c
@@ -26,6 +26,7 @@ static const char* g_Target;
 
 enum fixup_mode
 {
+    MODE_NONE = 0,
     MODE_LOADCONFIG,
     MODE_KERNELDRIVER,
     MODE_WDMDRIVER,
@@ -127,7 +128,7 @@ static int add_loadconfig(unsigned char *buffer, 
PIMAGE_NT_HEADERS nt_header)
     return 1;
 }
 
-static int driver_fixup(int mode, unsigned char *buffer, PIMAGE_NT_HEADERS 
nt_header)
+static int driver_fixup(enum fixup_mode mode, unsigned char *buffer, 
PIMAGE_NT_HEADERS nt_header)
 {
     /* GNU LD just doesn't know what a driver is, and has notably no idea of 
paged vs non-paged sections */
     for (unsigned int i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
@@ -174,23 +175,203 @@ static int driver_fixup(int mode, unsigned char *buffer, 
PIMAGE_NT_HEADERS nt_he
     return 0;
 }
 
+/* NOTE: This function tokenizes its parameter in place.
+ * Its format is: name[=newname][,[[!]{CDEIKOMPRSUW}][A{1248PTSX}]] */
+static int change_section_attribs(char* section_attribs, unsigned char* 
buffer, PIMAGE_NT_HEADERS nt_header)
+{
+    char *sectionName, *newSectionName;
+    char *attribsSpec, *alignSpec;
+    char *ptr;
+    DWORD dwAttribs[2]; /* Attributes to [0]: set; [1]: filter */
+    unsigned int i;
+    PIMAGE_SECTION_HEADER SectionTable, Section;
+
+    if (!section_attribs || !*section_attribs)
+    {
+        error("Section attributes specification is empty.\n");
+        return 1;
+    }
+
+    sectionName = section_attribs;
+
+    /* Find the optional new section name and attributes specifications */
+    newSectionName = strchr(section_attribs, '=');
+    attribsSpec = strchr(section_attribs, ',');
+    if (newSectionName && attribsSpec)
+    {
+        /* The attributes specification must be after the new name */
+        if (!(newSectionName < attribsSpec))
+        {
+            error("Invalid section attributes specification.\n");
+            return 1;
+        }
+    }
+    if (newSectionName)
+        *newSectionName++ = 0;
+    if (attribsSpec)
+        *attribsSpec++ = 0;
+
+    /* An original section name must be specified */
+    if (!*sectionName)
+    {
+        error("Invalid section attributes specification.\n");
+        return 1;
+    }
+    /* If a new section name begins, it must be not empty */
+    if (newSectionName && !*newSectionName)
+    {
+        error("Invalid section attributes specification.\n");
+        return 1;
+    }
+
+    /* The alignment specification is inside the attributes specification */
+    alignSpec = NULL;
+    if (attribsSpec)
+    {
+        /* Check for the first occurrence of the 'A' separator, 
case-insensitive */
+        for (ptr = attribsSpec; *ptr; ++ptr)
+        {
+            if (toupper(*ptr) == 'A')
+            {
+                alignSpec = ptr;
+                break;
+            }
+        }
+    }
+    if (alignSpec)
+        *alignSpec++ = 0;
+
+    /* But it's not supported at the moment! */
+    if (alignSpec && *alignSpec)
+    {
+        fprintf(stdout, "%s WARNING: '%s': %s", g_ApplicationName, g_Target,
+                "Section alignment specification not currently supported! 
Ignoring.\n");
+    }
+
+    /* Parse the attributes specification */
+    dwAttribs[0] = dwAttribs[1] = 0;
+    if (attribsSpec && *attribsSpec)
+    {
+        for (i = 0, ptr = attribsSpec; *ptr; ++ptr)
+        {
+            if (*ptr == '!')
+            {
+                /* The next attribute needs to be removed.
+                 * Any successive '!' gets collapsed. */
+                i = 1;
+                continue;
+            }
+
+            switch (toupper(*ptr))
+            {
+            case 'C':
+                dwAttribs[i%2] |= IMAGE_SCN_CNT_CODE;
+                break;
+            case 'D':
+                dwAttribs[i%2] |= IMAGE_SCN_MEM_DISCARDABLE;
+                break;
+            case 'E':
+                dwAttribs[i%2] |= IMAGE_SCN_MEM_EXECUTE;
+                break;
+            case 'I':
+                dwAttribs[i%2] |= IMAGE_SCN_CNT_INITIALIZED_DATA;
+                break;
+            case 'K': /* Remove the not-cached attribute */
+                dwAttribs[(i+1)%2] |= IMAGE_SCN_MEM_NOT_CACHED;
+                break;
+            case 'M':
+                dwAttribs[i%2] |= IMAGE_SCN_LNK_REMOVE;
+                break;
+            case 'O':
+                dwAttribs[i%2] |= IMAGE_SCN_LNK_INFO;
+                break;
+            case 'P': /* Remove the not-paged attribute */
+                dwAttribs[(i+1)%2] |= IMAGE_SCN_MEM_NOT_PAGED;
+                break;
+            case 'R':
+                dwAttribs[i%2] |= IMAGE_SCN_MEM_READ;
+                break;
+            case 'S':
+                dwAttribs[i%2] |= IMAGE_SCN_MEM_SHARED;
+                break;
+            case 'U':
+                dwAttribs[i%2] |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+                break;
+            case 'W':
+                dwAttribs[i%2] |= IMAGE_SCN_MEM_WRITE;
+                break;
+
+            default:
+                error("Invalid section attributes specification.\n");
+                return 1;
+            }
+
+            /* Got an attribute; reset the state */
+            i = 0;
+        }
+        /* If the state was not reset, the attributes specification is invalid 
*/
+        if (i != 0)
+        {
+            error("Invalid section attributes specification.\n");
+            return 1;
+        }
+    }
+
+    /* Find all sections with the given name, rename them and change their 
attributes */
+    Section = NULL;
+    SectionTable = IMAGE_FIRST_SECTION(nt_header);
+    for (i = 0; i < nt_header->FileHeader.NumberOfSections; ++i)
+    {
+        if (strncmp((char*)SectionTable[i].Name, sectionName, 
ARRAY_SIZE(SectionTable[i].Name)) != 0)
+            continue;
+
+        Section = &SectionTable[i];
+
+        if (newSectionName && *newSectionName)
+        {
+            memset(Section->Name, 0, sizeof(Section->Name));
+            strncpy((char*)Section->Name, newSectionName, 
ARRAY_SIZE(Section->Name));
+        }
+
+        /* First filter attributes out, then add the new ones.
+         * The new attributes override any removed ones. */
+        Section->Characteristics &= ~dwAttribs[1];
+        Section->Characteristics |=  dwAttribs[0];
+    }
+
+    /* If no section was found, return an error */
+    if (!Section)
+    {
+        error("Section '%s' does not exist.\n", sectionName);
+        return 1;
+    }
+
+    return 0;
+}
+
 static
 void
 print_usage(void)
 {
-    printf("Usage: %s <mode> <filename>\n", g_ApplicationName);
-    printf("Where <mode> is on of the following:\n");
-    printf("  --loadconfig          Fix the LOAD_CONFIG directory entry\n");
-    printf("  --kernelmodedriver    Fix code and data sections for driver 
images\n");
-    printf("  --wdmdriver           Fix code and data sections for WDM 
drivers\n");
-    printf("  --kerneldll           Fix code and data sections for Kernel-Mode 
DLLs\n");
-    printf("  --kernel              Fix code and data sections for kernels\n");
+    printf("Usage: %s <options> <filename>\n\n", g_ApplicationName);
+    printf("<options> can be one of the following options:\n"
+           "  --loadconfig          Fix the LOAD_CONFIG directory entry;\n"
+           "  --kernelmodedriver    Fix code and data sections for driver 
images;\n"
+           "  --wdmdriver           Fix code and data sections for WDM 
drivers;\n"
+           "  --kerneldll           Fix code and data sections for Kernel-Mode 
DLLs;\n"
+           "  --kernel              Fix code and data sections for kernels;\n"
+           "\n"
+           "and/or a combination of the following ones:\n"
+           "  --section:name[=newname][,[[!]{CDEIKOMPRSUW}][A{1248PTSX}]]\n"
+           "                        Overrides the attributes of a section, 
optionally\n"
+           "                        changing its name and its alignment.\n");
 }
 
 int main(int argc, char **argv)
 {
     int result = 1;
-    enum fixup_mode mode;
+    enum fixup_mode mode = MODE_NONE;
+    int i;
     FILE* file;
     size_t len;
     unsigned char *buffer;
@@ -199,41 +380,71 @@ int main(int argc, char **argv)
 
     g_ApplicationName = argv[0];
 
-    if (argc != 3)
+    /* Check for options */
+    for (i = 1; i < argc; ++i)
     {
-        print_usage();
-        return 1;
-    }
+        if (!(argv[i][0] == '-' && argv[i][1] == '-'))
+        {
+            /* We are out of options (they come first before
+             * anything else, and cannot come after). */
+            break;
+        }
 
-    if (strcmp(argv[1], "--loadconfig") == 0)
-    {
-        mode = MODE_LOADCONFIG;
-    }
-    else if (strcmp(argv[1], "--kernelmodedriver") == 0)
-    {
-        mode = MODE_KERNELDRIVER;
-    }
-    else if (strcmp(argv[1], "--wdmdriver") == 0)
-    {
-        mode = MODE_WDMDRIVER;
-    }
-    else if (strcmp(argv[1], "--kerneldll") == 0)
-    {
-        mode = MODE_KERNELDLL;
-    }
-    else if (strcmp(argv[1], "--kernel") == 0)
-    {
-        mode = MODE_KERNEL;
+        if (strcmp(&argv[i][2], "loadconfig") == 0)
+        {
+            if (mode != MODE_NONE)
+                goto mode_error;
+            mode = MODE_LOADCONFIG;
+        }
+        else if (strcmp(&argv[i][2], "kernelmodedriver") == 0)
+        {
+            if (mode != MODE_NONE)
+                goto mode_error;
+            mode = MODE_KERNELDRIVER;
+        }
+        else if (strcmp(&argv[i][2], "wdmdriver") == 0)
+        {
+            if (mode != MODE_NONE)
+                goto mode_error;
+            mode = MODE_WDMDRIVER;
+        }
+        else if (strcmp(&argv[i][2], "kerneldll") == 0)
+        {
+            if (mode != MODE_NONE)
+                goto mode_error;
+            mode = MODE_KERNELDLL;
+        }
+        else if (strcmp(&argv[i][2], "kernel") == 0)
+        {
+            if (mode != MODE_NONE)
+                goto mode_error;
+            mode = MODE_KERNEL;
+        }
+        else if (strncmp(&argv[i][2], "section:", 8) == 0)
+        {
+            /* Section attributes override, will be handled later */
+        }
+        else
+        {
+            fprintf(stderr, "%s ERROR: Unknown option: '%s'.\n", 
g_ApplicationName, argv[i]);
+            goto failure;
+    mode_error:
+            fprintf(stderr, "%s ERROR: Specific mode already set.\n", 
g_ApplicationName);
+    failure:
+            print_usage();
+            return 1;
+        }
     }
-    else
+    /* Stop now if we don't have any option or file */
+    if ((i <= 1) || (i >= argc))
     {
         print_usage();
         return 1;
     }
 
-    g_Target = argv[2];
+    g_Target = argv[i];
 
-    /* Read the whole file to memory. */
+    /* Read the whole file to memory */
     file = fopen(g_Target, "r+b");
     if (!file)
     {
@@ -251,12 +462,12 @@ int main(int argc, char **argv)
     }
 
     /* Add one byte extra for the case where the input file size is odd.
-       We rely on this in our crc calculation */
+       We rely on this in our checksum calculation. */
     buffer = calloc(len + 1, 1);
     if (buffer == NULL)
     {
         fclose(file);
-        error("Not enough memory available: (Needed %lu bytes).\n", len + 1);
+        error("Not enough memory available (Needed %lu bytes).\n", len + 1);
         return 1;
     }
 
@@ -264,7 +475,7 @@ int main(int argc, char **argv)
     fseek(file, 0, SEEK_SET);
     fread(buffer, 1, len, file);
 
-    /* Check the headers and save pointers to them. */
+    /* Check the headers and save pointers to them */
     dos_header = (PIMAGE_DOS_HEADER)buffer;
     if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
     {
@@ -279,10 +490,28 @@ int main(int argc, char **argv)
         goto Quit;
     }
 
-    if (mode == MODE_LOADCONFIG)
-        result = add_loadconfig(buffer, nt_header);
-    else
-        result = driver_fixup(mode, buffer, nt_header);
+    result = 0;
+
+    /* Apply mode fixups */
+    if (mode != MODE_NONE)
+    {
+        if (mode == MODE_LOADCONFIG)
+            result = add_loadconfig(buffer, nt_header);
+        else
+            result = driver_fixup(mode, buffer, nt_header);
+    }
+
+    /* Apply any section attributes override */
+    for (i = 1; (i < argc) && (result == 0); ++i)
+    {
+        /* Ignore anything but the section specifications */
+        if (!(argv[i][0] == '-' && argv[i][1] == '-'))
+            break;
+        if (strncmp(&argv[i][2], "section:", 8) != 0)
+            continue;
+
+        result = change_section_attribs(&argv[i][10], buffer, nt_header);
+    }
 
     if (!result)
     {

Reply via email to