Hi Guys
How a String Message Table is formed inside the rsrc section of a PE ?
I´m not talking about a Resource Script, but on how the script is created in raw inside a PE . Ex:
This..
#define IDS_HELLO 1
#define IDS_GOODBYE 2
STRINGTABLE
{
IDS_HELLO, "Hello"
IDS_GOODBYE, "Goodbye"
}
How is it organized ? How the Ids are created and where they are being placed ? Do it have any sort of structure related to it ?
I know they are formed by groups of 16 Unicode (unicode16) strings, but i don´t know what is the relation between their indexes and ids on the position they are created inside the resource section.
According to this
http://www.csn.ul.ie/~caolan/publink/winresdump/winresdump/doc/resfmt.txt, it says that:
"4.8 String Table Resources
These tables are constructed in blocks of 16 strings. The organization of these blocks of 16 is determined by the IDs given to
the various strings. The lowest four bits of the ID determine a string's position in the block. The upper twelve bits determine
which block the string is in. Each block of 16 strings is stored as one resource entry. Each string or error table resource block is
stored as follows:
[Normal resource header (type = 6 for strings)]
[Block of 16 strings. The strings are Pascal style with a WORD
length preceding the string. 16 strings are always written, even
if not all slots are full. Any slots in the block with no string
have a zero WORD for the length.]
It is important to note that the various blocks need not be written out in numerical order in the resource file. Each block is assigned
an ordinal ID. This ID is the high 12 bits of the string IDs in the block plus one (ordinal IDs can't be zero). The blocks are written
to the .RES file in the order the blocks are encountered in the .RC file, while the CVTRES utility will cause them to become ordered in
the COFF object, and hence the image file. "
Also, here is an article explaining t, but i didn´t understood.
https://titanwolf.org/Network/Articles/Article?AID=557d9a19-e07c-4eff-95cd-73306336fbf2#gsc.tab=0And below it shows some internal structures:
https://sourceware.org/legacy-ml/binutils/2007-05/msg00314/windint.h
/* A stringtable resource is a pointer to a rc_stringtable. */
typedef struct rc_stringtable
{
/* Each stringtable resource is a list of 16 unicode strings. */
struct
{
/* Length of string. */
rc_uint_type length;
/* String data if length > 0. */
unichar *string;
} strings[16];
} rc_stringtable;More references:
https://source.surroindustries.com/Cycle0/Foster/-/blob/51ad9f48c7d7e90792293e2312263b07b68bad77/Fedora/x86_64/surro-iso/build/binutils-2.29/binutils/resbin.cAlso..can it have a ID of 0 or it must always starts at 1 ?
When we have a multiline string, when encoding, they are generally appended a Line Feed (hex = 0A) as a paragraph mark. So, does the next line (That is part of the same string) represents another index ?
How to encode it ?
For example, say i have this as strings to be encoded:
Id Value String to be encoded
120 Hello World
147 Testing String Table
2580 This i a multiline string /n and i´m continuing the text after the line feed
I succeeded to decode it like this:
; References:
; http://www.csn.ul.ie/~caolan/publink/winresdump/winresdump/doc/resfmt.txt
; https://devblogs.microsoft.com/oldnewthing/20040130-00/?p=40813
; https://stackoverflow.com/questions/60564533/how-to-read-string-table-resources-for-given-language-into-map
; https://doxygen.reactos.org/df/d90/resources_8c_source.html#l00077
; Function parameters
; InputData - is the pointer to the IMAGE_RESOURCE_DATA_ENTRY corresponding to the leaf node of the resource. So it points to the structure that will point to the true data (The strings that are in Unicode)
; Output -An output buffer to store the decoded strings to be used later
; SrcId - The resource ID as it was found in the IMAGE_RESOURCE_DIRECTORY_ENTRY structure that lead to the true data.
Proc GetRsrcString:
Arguments @InputData, @Output, @SrcId
Local @NameInt, @iCounter, @Src, @FileLen, @Id, @NewSize
Uses esi, edi, ecx, edx
mov eax D@SrcId | and eax 0FFFF | mov W@NameInt ax
mov D@iCounter 0
mov esi D@InputData
mov edi D@Output
xor eax eax
.While eax < 16 ; Groups of 16
mov eax esi | movzx ecx W$eax | mov D@FileLen ecx
add esi 2
mov eax D@FileLen
.If eax <> 0
movzx eax W@NameInt | sub eax 1 | shl eax 4
movzx ecx W@iCounter | add eax ecx | movzx eax ax | mov D@Id eax
C_call FormatStr edi, {'#%d ', 0}, eax ; Print the correct Id of the string
add edi eax
mov eax D@FileLen
shl eax 1 | mov D@NewSize eax
call 'ntdll.RtlUnicodeToMultiByteN' edi, D@FileLen, &NULL, esi, eax ; Convert the Unicode to Ansi
add esi D@NewSize
add edi D@FileLen | mov W$edi CRLF | add edi 2
.End_If
inc D@iCounter
mov eax D@iCounter
.End_While
mov eax edi
EndP
The complete way the strings are mounted inside a PE is given by the image below. From images 1 to 3 i understood how it works, but on image 4 (the actual string table). How is it formed ? It don´[t seems to be they are created with a 16 Word group. And how they Ids are created on a way that don´pt overlap with each other ?
On this example, the rsrc section contains only 40 Strings Groups, each one of them with his own ID. The total amount of Strings are something around 380. So, how the IDs are related to each group on a way that it don´t overlap ? And what about the position
of each string inside a group how does it works and what is it relation to the ID ?

It seems to be a Structure formed by:
[StringRsrcGroup:
Group1Rsrc.Size: W$ 11
Group1Rsrc.Data: W$ "Hello World"
(...)
Group16Rsrc.Size: W$ 2
Group16Rsrc.Data: W$ "Hi"]
But...What if the 1st Chunk in the group is empty ? How is it related to the id or it´position on the 16 words chunk ? Ex:
[StringRsrcGroup:
Group1Rsrc.Size: W$ 0
Group1Rsrc.Data: W$ 0
Group2Rsrc.Size: W$ 0
Group2Rsrc.Data: W$ 0
Group3Rsrc.Size: W$ 11
Group3Rsrc.Data: W$ "Hello World"
(...)
Group16Rsrc.Size: W$ 2
Group16Rsrc.Data: W$ "Hi"]
Also, it seems that the maximum amount of Strings Ids is 4095, is that correct ?