A few days ago a colleage and I were looking at a bug:
Issue: Connectors with a policy containing ja char’s in
etc do not start up. Loading the policy in a browser, it is broken.
Okay, so let’s unpack that statement. Japanese characters in our configuration is causing issues.
To understand how to correct this, we have to understand a few background concepts.
When we generate an installer for any of the products we support (windows, mac, android, linux etc). We inject a custom configuration into the installer and sign the installer. The custom configuration includes input from our end users. This can be as simple as the name of a policy.
This specific defect was occurring with our windows agent.
To get to the bottom of this we will need to understand the PE format. Below I’m using pedump on a .net binary that a candidate submitted as a a sample solution to a programming problem.
λ pedump ~/development/candidates/<snip>/src/domain/bin/Debug/domain.dll
=== MZ Header ===
signature: "MZ"
bytes_in_last_block: 144 0x90
blocks_in_file: 3 3
num_relocs: 0 0
header_paragraphs: 4 4
min_extra_paragraphs: 0 0
max_extra_paragraphs: 65535 0xffff
ss: 0 0
sp: 184 0xb8
checksum: 0 0
ip: 0 0
cs: 0 0
reloc_table_offset: 64 0x40
overlay_number: 0 0
reserved0: 0 0
oem_id: 0 0
oem_info: 0 0
reserved2: 0 0
reserved3: 0 0
reserved4: 0 0
reserved5: 0 0
reserved6: 0 0
lfanew: 128 0x80
=== DOS STUB ===
00000000: 0e 1f ba 0e 00 b4 09 cd 21 b8 01 4c cd 21 54 68 |........!..L.!Th|
00000010: 69 73 20 70 72 6f 67 72 61 6d 20 63 61 6e 6e 6f |is program canno|
00000020: 74 20 62 65 20 72 75 6e 20 69 6e 20 44 4f 53 20 |t be run in DOS |
00000030: 6d 6f 64 65 2e 0d 0d 0a 24 00 00 00 00 00 00 00 |mode....$.......|
=== PE Header ===
signature: "PE\x00\x00"
# IMAGE_FILE_HEADER:
Machine: 332 0x14c x86
NumberOfSections: 3 3
TimeDateStamp: "1970-01-01 00:00:00"
PointerToSymbolTable: 0 0
NumberOfSymbols: 0 0
SizeOfOptionalHeader: 224 0xe0
Characteristics: 8450 0x2102 EXECUTABLE_IMAGE, 32BIT_MACHINE, DLL
# IMAGE_OPTIONAL_HEADER32:
Magic: 267 0x10b 32-bit executable
LinkerVersion: 8.0
SizeOfCode: 8192 0x2000
SizeOfInitializedData: 1536 0x600
SizeOfUninitializedData: 0 0
AddressOfEntryPoint: 15998 0x3e7e
BaseOfCode: 8192 0x2000
BaseOfData: 16384 0x4000
ImageBase: 4194304 0x400000
SectionAlignment: 8192 0x2000
FileAlignment: 512 0x200
OperatingSystemVersion: 4.0
ImageVersion: 0.0
SubsystemVersion: 4.0
Reserved1: 0 0
SizeOfImage: 32768 0x8000
SizeOfHeaders: 512 0x200
CheckSum: 0 0
Subsystem: 3 3 WINDOWS_CUI
DllCharacteristics: 34112 0x8540 DYNAMIC_BASE, NX_COMPAT, NO_SEH
TERMINAL_SERVER_AWARE
SizeOfStackReserve: 1048576 0x100000
SizeOfStackCommit: 4096 0x1000
SizeOfHeapReserve: 1048576 0x100000
SizeOfHeapCommit: 4096 0x1000
LoaderFlags: 0 0
NumberOfRvaAndSizes: 16 0x10
=== DATA DIRECTORY ===
EXPORT rva:0x 0 size:0x 0
IMPORT rva:0x 3e30 size:0x 4b
RESOURCE rva:0x 4000 size:0x 324
EXCEPTION rva:0x 0 size:0x 0
SECURITY rva:0x 0 size:0x 0
BASERELOC rva:0x 6000 size:0x c
DEBUG rva:0x 0 size:0x 0
ARCHITECTURE rva:0x 0 size:0x 0
GLOBALPTR rva:0x 0 size:0x 0
TLS rva:0x 0 size:0x 0
LOAD_CONFIG rva:0x 0 size:0x 0
Bound_IAT rva:0x 0 size:0x 0
IAT rva:0x 2000 size:0x 8
Delay_IAT rva:0x 0 size:0x 0
CLR_Header rva:0x 2008 size:0x 48
rva:0x 0 size:0x 0
=== SECTIONS ===
NAME RVA VSZ RAW_SZ RAW_PTR nREL REL_PTR nLINE LINE_PTR FLAGS
.text 2000 1e84 2000 200 0 0 0 0 60000020 R-X CODE
.rsrc 4000 324 400 2200 0 0 0 0 40000040 R-- IDATA
.reloc 6000 c 200 2600 0 0 0 0 42000040 R-- IDATA DISCARDABLE
=== RESOURCES ===
FILE_OFFSET CP LANG SIZE TYPE NAME
0x2258 0 0 716 VERSION #1
=== IMPORTS ===
MODULE_NAME HINT ORD FUNCTION_NAME
mscoree.dll 0 _CorDllMain
=== VERSION INFO ===
# VS_FIXEDFILEINFO:
FileVersion : 1.0.0.0
ProductVersion : 1.0.0.0
StrucVersion : 0x10000
FileFlagsMask : 0x3f
FileFlags : 0
FileOS : 4
FileType : 2
FileSubtype : 0
VarFileInfo : [ 0x7f, 0x4b0 ]
# StringTable 007f04b0:
Comments : ""
CompanyName : ""
FileDescription : "domain"
FileVersion : "1.0.0.0"
InternalName : "domain"
LegalCopyright : "Copyright © 2012"
LegalTrademarks : ""
OriginalFilename : "domain.dll"
ProductName : "domain"
ProductVersion : "1.0.0.0"
=== Packer / Compiler ===
MS Visual C# / Basic .NET
The PE format instructs the windows OS on how to execute the program. The
interesting part of this format is the .rsrc section that describes
resources that are embedded in the binary. This is where we inject the
custom configuration. With the resource injection we also have to update
the size of the resource.
Let’s take a closer look. Below is a dump of the resources in the binary. It shows a single resource with a size of 716, and name of #1.
λ pedump -R ~/development/candidates/<snip>/src/domain/bin/Debug/domain.dll
=== RESOURCES ===
FILE_OFFSET CP LANG SIZE TYPE NAME
0x2258 0 0 716 VERSION #1
This is where understanding encodings and the size becomes important.
Here’s an example in Ruby:
λ irb
irb(main):001:0> "M".size
=> 1
irb(main):002:0> "M".bytesize
=> 1
irb(main):003:0> "科".size
=> 1
irb(main):004:0> "科".bytesize
=> 3
So when calculating the size of the resource that is injected into the executable we need to use the byte size, not just the number of characters.
Which makes for a nice easy one line fix.
- write_resource_size(offset_to_size, content.size, injected_file)
+ write_resource_size(offset_to_size, content.bytesize, injected_file)
Happy hacking!