Mammon_'s Tales to his Grandson
On The Fruit of Labor


Project1 * Project2


Project One

The Target

Notepad is a program with which every user should be familiar: a very quick, very small (34K) windows text editor. It has quite a few limitations, such as editting only one file at a time, having a limited target file size, and displaying files in an uglyt system fixed font. It is this last shortcoming that we are going to change.


The Job

To begin with, open Notepad.exe in any win32 disassembler; I am using w32DASM as it is freely available (as a demo version) and fairly reliable. The first step is to NOT stare at the code until your eyes water, or to try to trace through the disassembled listing line-by-line. This is a surgical strike; we are after one thing and one thing only: a font.

Notepad is a system applet that uses a standard system font; the font will therefore be a windows system resource, and it will be in GDI32.dll (GDI manages objects such as pens, brushes, bitmaps, fonts, and Device Contexts; USER manages windows, menus, icons, controls, timers, task management, messaging, the clipboard, and networks; KERNEL handles memory management, dynamic linking, task scheduling, and program loading). Therefore we will use the Functions->Imports menu item in W32DASM and examine the GDI imports:

GDI32.AbortDoc
GDI32.CreateDCA
GDI32.CreateFontA
GDI32.DeleteDC
GDI32.DeleteObject
GDI32.EndDoc
GDI32.EndPage
GDI32.GetDeviceCaps
GDI32.GetStockObject
GDI32.GetTextCharset
....
CreateFontA appears at the end of the following section of code:
-----ASM Excerpt 1----------------------------------------------------------------------
	* Menu: MenuID_0001, Item: "Save"
	* String Resource ID=00001: "Cannot open the %% file.

Make sure a disk is in the drive y"
                                  |
:004037B2 6A01                    push 00000001
:004037B4 53                      push ebx
	* GDI32.SetBkMode, Ord:010Dh
                                  |
:004037B5 FF15C0724000            Call dword ptr [004072C0]
:004037BB 8D8558FFFFFF            lea eax, dword ptr [ebp+FFFFFF58]
	* GDI32.GetTextMetricsA, Ord:00CDh
                                  |
:004037C1 8B35BC724000            mov esi, dword ptr [004072BC]
:004037C7 50                      push eax
:004037C8 53                      push ebx
:004037C9 FFD6                    call esi
	* Menu: MenuID_0001, Item: "Page Setup..."
	* Dialog: DialogID_000E, CONTROL_ID:0020, "&Header:"
	* String Resource ID=00032: "%%"
                                  |
:004037CB 6A20                    push 00000020
:004037CD 8D4590                  lea eax, dword ptr [ebp-70]
:004037D0 50                      push eax
	* String Resource ID=00057: "Courier New"
                                 |
:004037D1 6A39                    push 00000039
:004037D3 FF3570514000            push dword ptr [00405170]
	* USER32.LoadStringA, Ord:0168h
                                  |
:004037D9 FF15B0734000            Call dword ptr [004073B0]
:004037DF 8D4D90                  lea ecx, dword ptr [ebp-70]
:004037E2 51                      push ecx
:004037E3 6A31                    push 00000031
:004037E5 6A00                    push 00000000
	* Menu: MenuID_0001, Item: "Page Setup..."
	* Dialog: DialogID_000E, CONTROL_ID:0020, "&Header:"
	* String Resource ID=00032: "%%"
                                  |
:004037E7 6A20                    push 00000020
:004037E9 6A00                    push 00000000
:004037EB FF75F8                  push [ebp-08]
:004037EE 6A00                    push 00000000
:004037F0 6A00                    push 00000000
:004037F2 6A00                    push 00000000
:004037F4 FFB574FFFFFF            push dword ptr [ebp+FFFFFF74]
:004037FA 6A00                    push 00000000
:004037FC 6A00                    push 00000000
:004037FE 6A00                    push 00000000
:00403800 FFB558FFFFFF            push dword ptr [ebp+FFFFFF58]
	* Reference To: GDI32.CreateFontA, Ord:002Bh       <---------------CreateFontA------
                                  |
:00403806 FF15C4724000            Call dword ptr [004072C4]
------------------------------------------------------------End of ASM Excerpt 1------------
It appears that CreateFontA is being called as part of a Save and/or Print dialog box; if you run Notepad.exe, you will see that this is the case--files are saved (in Wordpad format) or printed in Courier New, not in the system font. At any rate this code is called by a dialog box and not during the program startup--therefore it is not the program default font for which we are looking. The next candidate is GetStockObject. According to the Win32 API reference, "The GetStockObject function retrieves a handle to one of the predefined stock pens, brushes, fonts, or palettes. " Sounds like our target; here is the code leading up to this function:
-----ASM Excerpt 2---------------------------------------------------------------------
:004027A0 688C614000              push 0040618C
	* Data Obj ->"Edit"
                                  |
:004027A5 6890614000              push 00406190
:004027AA 6800020000              push 00000200
:004027AF FFD7                    call edi
:004027B1 A304604000              mov dword ptr [00406004], eax
:004027B6 3BC3                    cmp eax, ebx
:004027B8 0F8401030000            je 00402ABF
	* String Resource ID=00016: "Cannot find "%%""
                                  |
:004027BE 6A10                    push 00000010
	* GDI32.GetStockObject, Ord:00BCh
                                  |
:004027C0 FF1594724000            Call dword ptr [00407294]
:004027C6 6A00                    push 00000000
------------------------------------------------------------End of ASM Excerpt 2------------
When you disassemble a Windows API call, the parameters for the function are pushed onto the stack; the API function pops these parameters, then returns a result in the AX (and possibly the DX as well) register. These parameters are pushed in the order that they are required by the function prototype. The prototype for GetStockObject is as follows:
HGDIOBJ GetStockObject(
    int  fnObject 	// type of stock object 
   );
with the fnObject having one of the following parameters:
BLACK_BRUSH, DKGRAY_BRUSH, GRAY_BRUSH, HOLLOW_BRUSH, LTGRAY_BRUSH, NULL_BRUSH, WHITE_BRUSH, BLACK_PEN, NULL_PEN, WHITE_PEN, ANSI_FIXED_FONT, ANSI_VAR_FONT, DEVICE_DEFAULT_FONT, OEM_FIXED_FONT, SYSTEM_FONT, SYSTEM_FIXED_FONT, DEFAULT_PALETTE.
Since GetStockObject takes only one parameter, we know that the "00000010" that is pushed immediately before the call represents fnObject. But which value does 10 represent? For this we need to search WinGDI.h, located in the Include directory of any Windows C/C++ compiler. Searching this file for SYSTEM_FONT, we find the following definitions:
/* Stock Logical Objects */
#define WHITE_BRUSH         0
#define LTGRAY_BRUSH        1
#define GRAY_BRUSH          2
#define DKGRAY_BRUSH        3
#define BLACK_BRUSH         4
#define NULL_BRUSH          5
#define HOLLOW_BRUSH        NULL_BRUSH
#define WHITE_PEN           6
#define BLACK_PEN           7
#define NULL_PEN            8
#define OEM_FIXED_FONT      10
#define ANSI_FIXED_FONT     11
#define ANSI_VAR_FONT       12
#define SYSTEM_FONT         13
#define DEVICE_DEFAULT_FONT 14
#define DEFAULT_PALETTE     15
#define SYSTEM_FIXED_FONT   16
#if(WINVER >= 0x0400)
#define DEFAULT_GUI_FONT    17
So it appears that 10h, or 16 decimal, is the value for SYSTEM_FIXED_FONT, so that we can change the function call in our ASM listing to
:004027BE 6A10                    fnObject =  SYSTEM_FIXED_FONT;
:004027C0 FF1594724000            HGDIOBJ GetStockObject( fnObject );
or, more simply,
:004027BE 6A10FF1594724000        HGDIOBJ GetStockObject( SYSTEM_FIXED_FONT );
After some experimentation with a hex editor, I found that the only font which causes a change is DEFAULT_GUI_FONT, an option not listed in the Win32API. To change this parameter, we need to change the code at :004027BE from 6A10 to 6A11. So, load up your favorite hex editor and search for 3BC30F84010300006A10, followed by the bytes FF1594724000 (it is v-e-r-y important to patch the right piece of code). Change the 6A10 to 6A11, save the file, and you have your patched Notepad.


Notes

It may be helpful at this point to elaborate on how to read API calls in assembly. For pratcice, let's look at the CreateFontA call:

HFONT CreateFontA(
    int  nHeight,	        // logical height of font 
    int  nWidth,	        // logical average character width 
    int  nEscapement,	        // angle of escapement 
    int  nOrientation,	        // base-line orientation angle 
    int  fnWeight,	        // font weight 
    DWORD  fdwItalic,	        // italic attribute flag 
    DWORD  fdwUnderline,        // underline attribute flag 
    DWORD  fdwStrikeOut,        // strikeout attribute flag 
    DWORD  fdwCharSet,	        // character set identifier 
    DWORD  fdwOutputPrecision,	// output precision 
    DWORD  fdwClipPrecision,	// clipping precision 
    DWORD  fdwQuality,	        // output quality 
    DWORD  fdwPitchAndFamily,	// pitch and family 
    LPCTSTR  lpszFace 	        // address of typeface name string 
   );
So, before this call there will be pushed onto the stack 5 integers and 9 double-words (a Long Pointer--the LP of LPCTSTR--is a dword value). These can be deduced from the code as follows:
:004037DF 8D4D90                  lea ecx, dword ptr [ebp-70]
:004037E2 51                      push ecx        <--INT nHeight
:004037E3 6A31                    push 00000031   <--INT nWidth
:004037E5 6A00                    push 00000000   <--INT nEscapement
:004037E7 6A20                    push 00000020   <--INT nOrientation
:004037E9 6A00                    push 00000000   <--INT fnWeight
:004037EB FF75F8                  push [ebp-08]   <--DWORD fdwItalic
:004037EE 6A00                    push 00000000   <--DWORD fdwUnderline
:004037F0 6A00                    push 00000000   <--DWORD fdwStrikeout
:004037F2 6A00                    push 00000000   <--DWORD fdwCharset
:004037F4 FFB574FFFFFF            push dword ptr [ebp+FFFFFF74] <--DWORD fdwOutputPrecision
:004037FA 6A00                    push 00000000   <--DWORD fdwClipPrecision
:004037FC 6A00                    push 00000000   <--DWORD fdwQuality
:004037FE 6A00                    push 00000000   <--DWORD fdwPitchAndFamily
:00403800 FFB558FFFFFF            push dword ptr [ebp+FFFFFF58] <---DWORD: lpszFace 
:00403806 FF15C4724000            CreateFontA( );
This boils down to the following API call:
HFONT CreateFontA( [ebp-70], 31, NULL, 20, NULL, [ebp-08], NULL, NULL, NULL, [ebp+FFFFFF74], NULL, NULL, NULL, ebp+FFFFFF58] );
The HFONT indicates the return type; the line
:0040380C 8945E4                  mov dword ptr [ebp-1C], eax
shows the HFONT value, which is returned in eax, being passed to the variable [ebp-1C]. The following lines show the handle being tested to determine if it is valid or NULL; if valid the Font is selected via a call to SelectObject(), if NULL (je=jnz) the call is bypassed.
:0040380F 85C0                    test eax, eax     ; is eax=0/is HFONT=0
:00403811 740B                    je 0040381E       ; if yes jump to 0040381E
:00403813 50                      push eax          ; if pass HFONT as parameter 1 (HDC)
:00403814 53                      push ebx          ; pass EBX as parameter 2 (hGDIobj
:00403815 FF1590724000            Call GDI32.SelectObject, Ord:0106h


Project Two New: Updated and sent to the +HCU 9.18: See Fravia for details

The Target

Netscape is the HTML browser of choice, as far as I am concerned. I am currently using 3.01 gold, which has six useless buttons called "What's New", "What's Cool", "Destinations", "People", "Software", and "Net Search". The task here is to make these buttons do something useful. A quick note: netscape.exe for this version is 3+ MB and disassembles to a 45 MB ASM file. Be warned.


The Job

This is a relatively simple task. I checked the obvious places (the registry, INI files, etc) for the settings of the button I wanted to change the most ("Net Search"), and found nothing. I therefore disassembled netscape.exe to check the string/dialog refs in w32DASM (not a recommended technique, in this case), and sure enough, all of the URLs for these buttons were there (note: I had looked for them as plain ASCII text using XED editor and found nothing... therefore a simple hex editor will be of no use in this case). So on to the real technique...

Open up netscape.exe in BRW (available, last I checked, from ACP--fantastic site , BTW, good job ACP!) or your favorite resource editor (I recommend Borland or Symantec over the one that comes with VC++...the latest version of this IDE is too integrated; I no longer trust the tools to do their jobs correctly. Plus you must have MSIE installed to even use it...) and check out the String Tables. The ones for these useless buttons start at #621 (on my version, at least) and #624. Opening each of these tables, you will see first the URLs--all six of them--followed by the text of the buttons that load them. These are simple enough to change by directly overwriting the text with your own values and saving the file as netscape.exe. A quick patch, the only time it takes is to type in the URLs that you particularly favor. I changed the buttons to the following:

  • 621 (What's New): from ...whats-new.html to http://207.30.50.126/fravia/academy.htm (New Title: +HCU)
  • 622 (What's Cool): from ...whats-cool.html to http://kryten.eng.monash.edu.au/gspamt.html (New Title: Net Tools)
  • 623 (Destinations): from ...index.html to http://www.hotmail.com (New Title: HotMail)
  • 624 (Net Search): from ...search.html to http://cuiwww.unige.ch/eao/www/Internet/Nedashkovsky.html (New Title: Search Engines)
  • 625 (People): from ...white-pages.html to http://www.anonymizer.com/open.html (New Title: Anonymizer)
  • 626 (Software): from ...upgrades.html to http://www.fortunecity.com/skyscraper/firelli/29/killer.html (New Title: Applet Killer)

    You may wish to try some of these, they are pretty good pages (the last one is not yet finished). If I ever get around to adding buttons, I will be sure to update this project. Have fun!


    Notes

    ACP has an execllent essay on Fravia's site that details how to automatically kill cookies. Personally, I use CookiePal (mostly because of the sound effects that tell you when a site is trying to "cookie" you), but the technique is nonetheless excellent and illustrative of the type of patches that can be made to Netscape. I will try to sum up ACP's essay here:

  • 1: Run netscape, go into Soft-Ice and BPX MessageBoxA .
  • 2: Go to a page that has a cookie (ACP supplies a test page with his essay).
  • 3: Soft-Ice will pop up. Press F12 to continue with the program, and press the "Cancel" button for the cookie box.
  • 4: Soft-Ice will pop up again. F12 back until you reach the following code in netscape.exe:
        Add ESP,8     <-- we land HERE after the last 'P RET' !
        Test EAX,EAX
        JZ xxxxxxxx
    
  • 5: Scroll up the code window (CTRL-UpArrow) until you see the following code:
    
         Call xxxxxxxx     <-- this is some internal call, doesn't interest us!
         Mov EAX,[EBP+xx]
         Add ESP,8         <-- DO **NOT** skip this code line!
         Push EAX          <-- put a "JMP DO_NOT_SAVE_COOKIE" here.
         Mov EAX,[ESP+xx]
         Push EAX
         Mov EAX,[EBP+xx]
         Call [EBP+xx]     <-- our "ConfirmCoockie()" call.
         Add ESP,8         <-- ******* Where you started scrolling from ********
         Test EAX,EAX
         JZ DO_NOT_SAVE_COOKIE <-- jump out of the save coockie routine!
    
  • 6: The line Call [EBX+xx] calls the function ("ConfirmCookie") that displays the cookie dialog box; it returns EAX=0 if you pressed Cancel, and EAX=1 if you pressed OK. You want to skip this call entirely, so ACP recommends putting a Jump to the JNZ line in place of the first Push EAX line. To do this, in Soft-Ice you must assemble (A) the command JMP xxxx:xxxx (with the x's being replaced with the address of the JNZ statement) at the address of the first Push EAX statement. The patch, as implemented by ACP for Netscape 3.0 gold, will be as follows:
     Offset     Old    New
           00095788:  50     E9
           00095789:  8B     74
           0009578A:  44     20
           0009578B:  24     00
           0009578C:  3C     00
    


    Project Three

    The Target

    Explorer.exe has proven a tough target to reverse due to its size (200K) and the unrecognized (undocumented?) resources used by Microsoft (namely but not limited to the TaskBar). Borland Resource Workshop patently refuses to disassenble Explorer, while Symantec Resource Editor gives only a partial listing. What this project will consist of, then, is an examination of the PE header itself and a hexdump of the program to identify and alter these mysterious, resource-editor-crashing resources.


    The Job

    Still under development

    The hex editor used to wade through explorer.exe in this project is Hiew 5.66; it and HED are the only known hex editors that are designed for Windows 95 reverse-engineering/cracking. Hiew was chosen over HED for its better interface (the Fkeys are far superior to a menu in a console app) and its file header-parsing functionality.

    The PE file header is the most important part of an executable file for reverse-engineering purposes. For the most part, PE header parsing is performed automatically by disassemblers and "dump" programs, so for many engineers it is an unknown structure. There are times, however, when you may not have the tools or time to disassemble an .exe, or the .exe itself may not disassemble correctly; in these cases the disassembly must be done manually, and a working knowledge of the PE header will prove vital. Information on the PE file header format can be obtained from Micro$oft or VLAD; these two sources read together are somewhat contradictory--it is advisable to use the M$oft document for reference (if you can get used to "short" instead of "word" and "long" instead of "DW") and the VLAD document for examples.

    The PE file header contains information about the file that is needed by Windows to load and execute that file correctly. Synopsis of the information it contains: Target CPU, Date/Time Stamp, OS Version, Subsystem Version, Magic Number (heh), Size of Code, Size of Image, Size of Initialized Data, Size of Uninitialized Data, Size of Headers, Base of Code, Base of Data, Image Base, File Alignment, Number of Sections, Number of Directories, Size of Optional (PE) Header, Linker Version, Image Version, Entrypoint RVA (Relative Virtual Address...relative to the ImageBase), Stack, Heap, and Checksum. Note that the Image Base is the address to which the program requests itself be loaded; File Alignment is responsible for "padding" each section of the file with null characters, for every section must begin and end on a multiple of File Alignment.

    The first part of the PE header contains the summary information listed above; after that, it is divided into a number of sections, of which there are nine types (note that not all need be present): .text (executable code), .bss (uninitialized data, eg static variables), .rdata (read-only data, eg literal strings, constants, debug dir info), .data (global variables), .rsrc (resource tables/data), .edata (export data), .idata (import data), .pdata (not discussed...possibly fixups), and .debug (debug information)--explorer.exe also has a .reloc section. The total number of sections (or "objects") contained in the header is listed in the header summary (see above); the list of which sections are present and where they are located (relative to the Image Base) is called the Object Table. This should suffice as an introduction to file headers for the purpose of this project; those unfamiliar with the PE header format are encouraged to read (or rather, skim) both of the above-mentioned documents and play with Hiew's header viewing capabilities.

    From here on only the resource section or object will be of interest; the rest of the PE header is of little or no consequence. The .rsrc section begins with an entry in the Object Table labelled .rsrc (at offset 000001F0 in Hiew), which is followed by the following "summary" information (displayed by pressing F8 in Hiew to bring up the PE header summary, then F6 to bring up the object table...be sure to compare this with the bytes following x01F0 so you know exactly where Hiew gets its information from): Virtual Size x0000A774 bytes, RVA x00027000, Physical Size x0000A800 bytes, Offset x00024600, Flag 40000040 (Readable/Initialized Data Object...see VLAD re the Object Table Flags). Note that this Object Table Entry points to the start of the .rsrc section (x00027000), which is also the location of the Resource directory. To view the directories of a file, press F8 in Hiew to bring up the PE header, then F7 to list the directories...notice the wealth of information which you can browse by pressing enter on any of the selections: Exported functions, Imported functions, Resources, Fixups, Debug information (keep in mind that directories in this list with a "000000" address are not present in the file). Select the Resources option to have Hiew change the addresses to RVAs (which will be useful when working with data at offsets from that RVA later on) and change the cursor position to x00027000 (which will be the base from which all Resource data offsets will be calculated).

    The structure for the root Resource Directory is as follows:

    DWORD Characteristics
    DWORD Time/Date Stamp
    WORD Major Version
    WORD Minor Version
    WORD Number of Named Entries
    WORD Number Of ID Entries
    
    The first line of the Resource Directory will look like this:
    
     27000:  00 00 00 00 C9 5D F3 2F - 00 00 00 00 00 00 0A 00       É]ó/      ú 
      Characteristics (4 bytes):     00000000
      Time/Date Stamp (4 bytes):     C95DF32F
      Major Version (2 bytes):           0000
      Minor Version (2 bytes):           0000
      # Of Named Resources (2 bytes):    0000
      # Of Numbered Resources (2 bytes): 000A (10)     
    This is a standard directory header: it lists the flags or characteristics of the directory, the time/date on which the directory was last modified, the major/minor version of the file (the programmer can set this), the number of subdirectories (or data) identified by names (note: this only counts 1 level, i.e., this is the number of named subdirectories that branch from this main directory), and the number of subdirectories identified by numbers (note that a subdirectory or data entry will be counted in either Named or Numbered, not in both).

    The structure of a subdirectory is as follows:

    DWORD Name (Type ID)
    DWORD Offset to Data
    
    Immediately following this line will be the ten subdirectories (note that if you use a standard hexdump program instead of Hiew, all address will be based from 24600 instead of 27000, for hexdump programs will ignore FileAlignment and use the Physical Offset of the Resource Directory...this will cause problems later when data is specified at addresses--such as x 0002B694--which assume that the code is based on the RVA):
    
    Directory 1
     27010:  01 00 00 00 60 00 00 80 - 02 00 00 00 78 00 00 80   ú   `  €ú   x  €
      Type ID: 00000001 Offset: 80000060 (Subdir @ 27060)
      Type ID: 00000002 Offset: 80000078 (Subdir @ 27078)
     27020:  03 00 00 00 D8 00 00 80 - 04 00 00 00 58 01 00 80   ú   Ø  €ú   Xú €
      Type ID: 00000003 Offset: 800000D8 (Subdir @ 270D8)
      Type ID: 00000004 Offset: 80000158 (Subdir @ 27158)
     27030:  05 00 00 00 98 01 00 80 - 06 00 00 00 E0 01 00 80   ú   ˜ú €ú   àú €
      Type ID: 00000005 Offset: 80000198 (Subdir @ 27198)
      Type ID: 00000006 Offset: 800001E0 (Subdir @ 271E0)
     27040:  09 00 00 00 98 02 00 80 - 0C 00 00 00 C0 02 00 80   ú   ˜ú €ú   Àú €
      Type ID: 00000009 Offset: 80000298 (Subdir @ 27298)
      Type ID: 0000000C Offset: 800002C0  (Subdir @ 272C0)
     27050:  0E 00 00 00 D8 02 00 80 - 10 00 00 00 28 03 00 80   ú   Øú €ú   (ú €
      Type ID: 0000000E Offset: 800002D8 (Subdir @ 272D8)
      Type ID: 00000010 Offset: 80000328 (Subdir @ 27328)
    For those that do not know why all of the numbers seem "backwards" in the hex code, this is because the Intel processor takes in data using a "little-endian" approach---that is, it takes the lowest bit/byte first (the "Ones" column), and the highest bit/byte last (the "tens", then the "hundreds"). Thus, the number x9800 becomes 00 98 in a hex listing, the number x00027000 becomes 00 70 02 00, and the number x10 stays 10. Note that the 8 in the first byte od the offset indicates that this is a subdirectory entry as opposed to a data entry.

    Notice the Type IDs: these tell what type of resource each subdirectory contains (very important!) Type IDs can be resolved to meaningful strings by referring to the Windows 95 include files. Typing grep32 "MAKEINTRES" f:\devstudio\vc\include\*.* (adjust, I need not say, to suit your own grep file and include path) reveals the following string definitions:

    
    f:\devstudio\vc\include\mapiwin.h:#define MAKEINTRESOURCEA            MAKEINTRESOURCE
    f:\devstudio\vc\include\penwin.h:#define IDC_PEN                         MAKEINTRESOURCE(32631)
    f:\devstudio\vc\include\penwin.h:#define IDC_ALTSELECT             MAKEINTRESOURCE(32501)
    ...
    f:\devstudio\vc\include\winuser.h:#define RT_CURSOR              MAKEINTRESOURCE(1)
    f:\devstudio\vc\include\winuser.h:#define RT_BITMAP                 MAKEINTRESOURCE(2)
    f:\devstudio\vc\include\winuser.h:#define RT_ICON                     MAKEINTRESOURCE(3)
    f:\devstudio\vc\include\winuser.h:#define RT_MENU                   MAKEINTRESOURCE(4)
    f:\devstudio\vc\include\winuser.h:#define RT_DIALOG                 MAKEINTRESOURCE(5)
    f:\devstudio\vc\include\winuser.h:#define RT_STRING                 MAKEINTRESOURCE(6)
    f:\devstudio\vc\include\winuser.h:#define RT_FONTDIR               MAKEINTRESOURCE(7)
    f:\devstudio\vc\include\winuser.h:#define RT_FONT                     MAKEINTRESOURCE(8)
    f:\devstudio\vc\include\winuser.h:#define RT_ACCELERATOR      MAKEINTRESOURCE(9)
    f:\devstudio\vc\include\winuser.h:#define RT_RCDATA                 MAKEINTRESOURCE(10)
    f:\devstudio\vc\include\winuser.h:#define RT_MESSAGETABLE    MAKEINTRESOURCE(11)
    f:\devstudio\vc\include\winuser.h:#define RT_GROUP_CURSOR        
                                                                       MAKEINTRESOURCE((DWORD)RT_CURSOR + DIFFERENCE)
    f:\devstudio\vc\include\winuser.h:#define RT_GROUP_ICON   
                                                                       MAKEINTRESOURCE((DWORD)RT_ICON + DIFFERENCE)
                                                                       ;note DIFFERENCE is set to 11 in WinUser.h
    f:\devstudio\vc\include\winuser.h:#define RT_VERSION              MAKEINTRESOURCE(16)
    f:\devstudio\vc\include\winuser.h:#define RT_DLGINCLUDE       MAKEINTRESOURCE(17)
    f:\devstudio\vc\include\winuser.h:#define RT_PLUGPLAY          MAKEINTRESOURCE(19)
    f:\devstudio\vc\include\winuser.h:#define RT_VXD                     MAKEINTRESOURCE(20)
    f:\devstudio\vc\include\winuser.h:#define RT_ANICURSOR        MAKEINTRESOURCE(21)
    f:\devstudio\vc\include\winuser.h:#define RT_ANIICON              MAKEINTRESOURCE(22)
    f:\devstudio\vc\include\winuser.h:#define IDC_ARROW              MAKEINTRESOURCE(32512)
    f:\devstudio\vc\include\winuser.h:#define IDC_IBEAM                MAKEINTRESOURCE(32513)
    ..
    f:\devstudio\vc\include\winuser.h:#define IDI_EXCLAMATION   MAKEINTRESOURCE(32515)
    f:\devstudio\vc\include\winuser.h:#define IDI_ASTERISK          MAKEINTRESOURCE(32516)
    f:\devstudio\vc\include\winuser.h:#define IDI_WINLOGO          MAKEINTRESOURCE(32517)
    
    Therefore the subdirectories will contain resources of type RT_CURSOR, RT_BITMAP, RT_ICON, RT_MENU, RT_DIALOG, RT_STRING, RT_ACCELERATOR, RT_GROUP_CURSOR, RT_GROUP_ICON, and RT_VERSION.

    After the "root" resource directory comes immediately the first subdirectory, following the same structure:

    
    Directory 1.1
    27060:  00 00 00 00 C9 5D F3 2F - 00 00 00 00 00 00 01 00       É]ó/      ú 
      Characteristics: 00000000
      Time/Date Stamp: C95DF32F
      M/m Version:     00000000
      # Of Named   : 0000
      # Of ID      : 0001      
    
    From here on the first line of any directory can be safely ignored, except for the "Number of Entries" bytes at xE-F. This (level-2) subdirectory has one entry:
    
     27070:  0F 00 00 00 40 03 00 80 - 00 00 00 00 C9 5D F3 2F   ú   @ú €    É]ó/
      ID: 0000000F Offset: 80000340 (Subdir @ 27340)
      Characteristics: 00000000 ; directory 1.2
      Time/Date Stamp: C95DF32F ; directory 1.2
    
    Another subdirectory (the time/date stamp is the beginning of the next Level-2 subdirectory...ignore it); the ID field this time refers to the "name" of the resource: resource #0F, or resource 15. Jumping to x27340 reveals the following entry:
    
    Directory 1.1.1
     27340:  00 00 00 00 C9 5D F3 2F - 00 00 00 00 00 00 01 00       É]ó/      ú 
      Characteristics: 00000000
      Time/Date Stamp: C95DF32F
      M/m Version:     00000000
      # Of Named   :   0000
      # Of ID      :   0001      
     27350:  09 04 00 00 00 0A 00 00 - 00 00 00 00 C9 5D F3 2F   úú   ú      É]ó/
      ID: 00000409 Offset: 00000A00 (Subdir @ 27A00)
      Characteristics: 00000000 ;directory 1.2.1
      Time/Date Stamp: C95DF32F ;directory 1.2.1
    
    Notice the lack of a leading "8" in this offset...this is a "leaf node" (as opposed to a "subdirectory node"--or "root node"?) that points to a data entry at xA00, which will have the following format:
    DWORD Offset to Data
    DWORD Size
    DWORD CodePage
    DWORD Reserved
    
    At x27A00 appears the data entry (keep track of this...the info here is at level 1.1.1.1, and there points to the actual data...no wonder the OS is so huge and slow) :
    
    Directory 1.1.1.1
     27A00:  A0 B0 02 00 34 01 00 00 - 00 00 00 00 00 00 00 00   €~ú 4ú          
      Offset:   0002B0A0  Size :    00000134 bytes  
      CodePage: 00000000  Reserved: 00000000
     27A10:  E8 B1 02 00 E8 00 00 00 - 00 00 00 00 00 00 00 00   ´ú è           
     27A20:  D0 B2 02 00 3C 02 00 00 - 00 00 00 00 00 00 00 00   œ€ú <ú          
    
    There it is--this is the data relocation table. Resource 1 of Type 1 consists of x134 bytes of data at x2B0A0. But that is not all...following this is every other resource data relocation: A10 shows x0E8 bytes of data at x2B1E8 (Resource 1 of Type 2), A20 shows x23C bytes of data at 2B2D0 (Resource 2 of Type 2), and so on. This is a shortcut: after getting the basic structure (types of resources, and how many of each type) from the root (Level 1) directory, you can pull all of the data relocations from this table and "plug them in" to the skeleton provided by the root directory.

    To verify this, the entire directory tree was traversed and labelled. The explorer.exe PE header .rsrc directory has the following structure (for reference only; if you read this your eyes will glaze over):

    
    Level 1: 10 Entries
    	1. 1 Entry (x0060)s: Type ID 01 (RT_CURSOR)
    		1. 1 Entry (x0328)s: Name ID 0F
    			1.Resource #00000409 @ x0A00 
    				1. 00000134 bytes at 00027E80  
    	2. 10 Entries (x0078)s: Type ID 02 (RT_BITMAP)
    		1. 1 Entry (x0358)s: Name ID 8F
    			1. Resource #00000409 @ x0A10
    				1.  000000E8 bytes at 00027FB4 
    		2. 1 Entry  (x0370)s: Name ID 90
    			1. Resource #00000409 @  x0A20
    				1. 0000023C bytes at 0002809C
    		3. 1 Entry (x0388)s: Name ID 91
    			1. Resource #00000409 @ x0A30
    				1. 00000186 bytes at 000282D8
    		4. 1 Entry (x03A0)s: Name ID 95
    			1. Resource #00000409 @ x0A40
    				1. 00001398 bytes at 00028460
    		5. 1 Entry (x03B8)s: Name ID 96 
    			1. Resource #00000409 @ x0A50
    				1. 00000C04 bytes at 000297F8
    		6. 1 Entry (x03D0)s: Name ID 97
    			1. Resource #00000409 @ x0A60
    				1. 00000558 bytes at 0002A3Fc
    		7. 1 Entry (x03E8)s: Name ID 98
    			1. Resource #00000409 @ x0A70
    				1. 000000FE bytes at 0002A954
    		8. 1 Entry (x0400)s: Name ID 99
    			1. Resource #00000409 @ x0A80
    				1. 000001A8 bytes at 0002AA54
    		9. 1 Entry (x0418)s: Name ID 9D
    			1. Resource #00000409 @ x0A90
    				1. 0000051C bytes at 0002ABFC
    		A. 1 Entry (x0430)s: Name ID A0
    			1. Resource #00000409 @ x0AA0
    				1. 000000EC bytes at 0002B118
    	3. 15 Entries (x00D8)s: Type ID 03 (RT_ICON)
    		1.  1 Entry (x0448)s: Name ID 01
    			1. Resource #00000409 @ x0AB0
    				1. 000002E8 bytes at 0002B204
    		2. 1 Entry (x0460)s: Name ID 02
    			1. Resource #00000409 @ x0AC0
    				1. 00000128 bytes at 0002B4EC
    		3. 1 Entry (x0478)s: Name ID 03
    			1. Resource #00000409 @ x0AD0
    				1. 00000130 bytes at 0002B614
    		4. 1 Entry (x0490)s: Name ID 04
    			1. Resource #00000409 @ x0AE0
    				1. 000002E8 bytes at 0002B744
    		5. 1 Entry (x04A8)s: Name ID 05
    			1. Resource #00000409 @ x0AF0
    				1. 00000128 bytes at 0002BA2C
    		6. 1 Entry (x04C0)s: Name ID 06
    			1. Resource #00000409 @ x0B00
    				1. 000002E8 bytes at 0002BB54
    		7. 1 Entry (x04D8)s: Name ID 07
    			1. Resource #00000409 @ x0B10
    				1. 00000128 bytes at 0002BE3C
    		8. 1 Entry (x04F0)s: Name ID 08
    			1. Resource #00000409 @ x0B20
    				1. 000002E8 bytes at 0002BF64
    		9. 1 Entry (x0508)s: Name ID 09
    			1. Resource #00000409 @ x0B30
    				1. 00000128 bytes at 0002C24C
    		A. 1 Entry (x0520)s: Name ID 0A
    			1. Resource #00000409 @ x0B40
    				1. 000002E8 bytes at 0002C374
    		B. 1 Entry (x0538)s: Name ID 0B
    			1. Resource #00000409 @ x0B50
    				1. 00000128 bytes at 0002C65C
    		C. 1 Entry (x0550)s: Name ID 0C
    			1. Resource #00000409 @ x0B60
    				1. 000002E8 bytes at 0002C784
     		D. 1 Entry (x0568)s: Name ID 0D
    			1. Resource #00000409 @ x0B70
    				1. 000002E8 bytes at 0002CA6C
    		E. 1 Entry (x0580)s: Name ID 0E
    			1. Resource #00000409 @ x0B80
    				1. 000002E8 bytes at 0002CD54
    	4. 6 Entries (x158)s:  Type ID 04 (RT_MENU)
    		1. 1 Entry (x0598)s: Name ID C9
    			1. Resource #00000409 @ x0B90
    				1. 00000370 bytes at 0002D03C
    		2. 1 Entry (x05B0)s: Name ID CA
    			1. Resource #00000409 @ x0BA0
    				1. 000002A0 bytes at 0002D3AC
    		3. 1 Entry (x05C8)s: Name ID CC
    			1. Resource #00000409 @ x0BB0
    				1. 000001F8 bytes at 0002D64C
    		4. 1 Entry (x05E0)s: Name ID CD
    			1. Resource #00000409 @ x0BC0
    				1. 00000174 bytes at 0002D844
    		5. 1 Entry (x05F8)s: Name ID CE
    			1. Resource #00000409 @ x0BD0
    				1. 00000038 bytes at 0002D9B8
    		6. 1 Entry (x0610)s: Name ID CF
    			1. Resource #00000409 @ x0BE0
    				1. 00000058 bytes at 0002D9F0
    	5.  7 Entries (x198)s:Type ID 05 (RT_DIALOG)
    		1. 1 Entry (x0628)s: Name ID 06
    			1. Resource #00000409 @ x0BF0
    				1. 00000166 bytes at 0002DA48
    		2. 1 Entry (x0640)s: Name ID 07
    			1. Resource #00000409 @ x0C00
    				1. 0000023C bytes at 0002DBB0
    		3. 1 Entry (x0658)s: Name ID 08
    			1. Resource #00000409 @ x0C10
    				1. 000002DE bytes at 0002DDEC
    		4. 1 Entry (x0670)s: Name ID 09
    			1. Resource #00000409 @ x0C20
    				1. 00000350 bytes at 0002E0CC
    		5. 1 Entry (x0688)s: Name ID 0B
    			1. Resource #00000409 @ x0C30
    				1. 000002B0 bytes at 0002E41C
    		6. 1 Entry (x06A0)s: Name ID 0C
    			1. Resource #00000409 @ x0C40
    				1. 000003D8 bytes at 0002E6CC
    		7. 1 Entry (x06B8)s: Name ID 0D
    			1. Resource #00000409 @ x0C50
    				1. 000003B4 bytes at 0002EAA4
    	6. 21 Entries (x1E0)s: Type ID 06 (RT_STRING)
    		1. 1 Entry (x06D0)s: Name ID 20
    			1. Resource #00000409 @ x0C60
    				1. 000001B8 bytes at 0002EE58
    		2. 1 Entry (x06E8)s: Name ID 21
    			1. Resource #00000409 @ x0C70
    				1. 000002E6 bytes at 0002F010
    		3. 1 Entry (x0700)s: Name ID 22
    			1. Resource #00000409 @ x0C80
    				1. 0000068E bytes at 0002F2F8
    		4. 1 Entry (x0718)s: Name ID 23
    			1. Resource #00000409 @ x0C90
    				1. 00000022 bytes at 0002F988
    		5. 1 Entry (x0730)s: Name ID 25
    			1. Resource #00000409 @ x0CA0
    				1. 00000760 bytes at 0002F9AC
    		6. 1 Entry (x0748)s: Name ID 26
    			1. Resource #00000409 @ x0CB0
    				1. 000001E8 bytes at 0003010C
    		7. 1 Entry (x0760)s: Name ID 2C
    			1. Resource #00000409 @ x0CC0
    				1. 00000362 bytes at 000302F4
    		8. 1 Entry (x0778)s: Name ID 2D
    			1. Resource #00000409 @ x0CD0
    				1. 00000404 bytes at 00030658
    		9. 1 Entry (x0790)s: Name ID 33
    			1. Resource #00000409 @ x0CE0
    				1. 0000008C bytes at 00030A5C
    		A. 1 Entry (x07A8)s: Name ID 37
    			1. Resource #00000409 @ x0CF0
    				1. 0000008E bytes at 00030AE8
    		B. 1 Entry (x07C0)s: Name ID 3B
    			1. Resource #00000409 @ x0D00
    				1. 0000007C bytes at 00030B78
    		C. 1 Entry (x07D8)s: Name ID 3F
    			1. Resource #00000409 @ x0D10
    				1. 0000007C bytes at 00030BF4
    		D. 1 Entry (x07F0)s: Name ID 43
    			1. Resource #00000409 @ x0D20
    				1. 0000006C bytes at 00030C70
    		E. 1 Entry (x0808)s: Name ID 47
    			1. Resource #00000409 @ x0D30
    				1. 00000062 bytes at 00030CDC
    		F. 1 Entry (x0820)s: Name ID 33
    			1. Resource #00000409 @ x0D40
    				1. 00000036 bytes at 00030D40
    		10. 1 Entry (x0838)s: Name ID 35
    			1. Resource #00000409 @ x0D50
    				1. 0000014A bytes at 00030D78
    		11. 1 Entry (x0850)s: Name ID 37
    			1. Resource #00000409 @ x0D60
    				1. 00000194 bytes at 00030EC4
    		12. 1 Entry (x0868)s: Name ID 39
    			1. Resource #00000409 @ x0D70
    				1. 0000012E bytes at 00031058
    		13. 1 Entry (x0880)s: Name ID 3B
    			1. Resource #00000409 @ x0D80
    				1. 000000DE bytes at 00031188
    		14. 1 Entry (x0898)s: Name ID 43
    			1. Resource #00000409 @ x0D90
    				1. 00000098 bytes at 00031268
    		15. 1 Entry (x08B0): Name ID 45
    			1. Resource #00000409 @ x0DA0
    				1. 00000038 bytes at 00031300
    	7. 3 Entries (x298)s: Type ID 09 (RT_ACCELERATOR)
    		1. 1 Entry (x08C8)s: Name ID FA
    			1. Resource #00000409 @ x0DB0
    				1. 00000080 bytes at 00031338
    		2. 1 Entry (x08E0)s: Name ID FB
    			1. Resource #00000409 @ x0DC0
    				1. 00000048 bytes at 000313B8
    		3. 1 Entry (x08F8)s: Name ID FC
    			1. Resource #00000409 @ x0DD0
    				1.00000038 bytes at 00031400
    	8. 1 Entry (x2C0)s: Type ID 0C (RT_GROUP_CURSOR)
    		1. 1 Entry (x0910)s: Name ID 65
    			1. Resource # 00000409 @ (x0DE0)
    				1. 00000014 bytes at 00031438
    	9. 8 Entries  (x2D8)s: Type ID 0E ((RT_GROUP_ICON)
    		1. 1 Entry (x0928)s: Name ID 64
    			1. Resource #00000409 @ x0DF0
    				1. 00000022 bytes at 0003144C
    		2. 1 Entry (x0940)s: Name ID 65
    			1. Resource #00000409 @ x0E00
    				1. 00000030 bytes at 00031470
    		3. 1 Entry (x0958)s: Name ID 66
    			1. Resource #00000409 @ x0E10
    				1. 00000022 bytes at 000314A0
    		4. 1 Entry (x0970)s: Name ID 67
    			1. Resource #00000409 @ x0E20
    				1. 00000022 bytes at 000314C4
    		5. 1 Entry (x0988)s: Name ID 68
    			1. Resource #00000409 @ x0E30
    				1. 00000022 bytes at 000314E8
    		6. 1 Entry (x09A0)s: Name ID 69
    			1. Resource #00000409 @ x0E40
    				1. 00000014 bytes at 0003150C
    		7. 1 Entry (x09B8)s: Name ID 6B
    			1. Resource #00000409 @ x0E50
    				1. 00000014 bytes at 00031520
    		8. 1 Entry (x09D0)s: Name ID 6C
    			1. Resource #00000409 @ x0E60
    				1. 00000014 bytes at 00031534
    	A. 1 Entry (x328)s: Type ID 10 (RT_VERSION)
    		1. 1 Entry (x09E8)s: Name ID 01
    			1. Resource #00000409 @ x0E70
    				1. 00000334 bytes at 00031548
    


    Notes

    Robert Brooks is developing a freeware resource editor called ResHack.


    Home * Tools * 95/NT Tech Info * Links