First off, to be able to do this we must have an uncompressed bootmgr. I took bootmgr.exe version 6.1.7600.16385 and attached the vista sp0 stub to it. Then I deleted the embedded digital certificate and some unneeded part of the xsl resource so that total size got below 512 kb. Then checksum in the stub was deactivated and the self signature validation was deactivated as well. That means you don't have to configure TESTSIGNING and NOINTEGRITYCHECKS in the BCD store.
Here's a special version suitable for this task: http://www.mediafire.com/file/8gwdlwr2n ... ATCHED.rar
The only parts of the wim header that changes when switching boot image is rhBootMetaData and dwBootIndex. That is at 0x60, 0x68, 0x70 and 0x78. The important thing with the patched bootmgr is that the wim header is patched in memory before it is mounted onto boot.sdi. By doing that we can boot from any image inside the wim. There's a special place reserved in my bootmgr for these new values to be written by grub4dos. Location is at 0x654C4, 0x654CC, 0x654D4 and 0x654DC. Grub4dos will map bootmgr (or lets call it wimpatched just to make a distinction) to the (rd) device and patch it before chainloading.
JFX made a great tool to create your menu.lst based on a target wim; http://www.mediafire.com/file/kd92y1aj3 ... heckWIM.7z
My sample menu.lst used to choose from 4 different images inside the same wim;
- Code: Select all
title Boot image 1 in boot.wim (Active @ Boot Disk)
map --mem /wimpatched (rd)
write --offset=0x654C4 (rd)+1 \x90\x39\x02
write --offset=0x654CC (rd)+1 \xD5\xDC\x69\x07
write --offset=0x654D4 (rd)+1 \xC0\x77\x08
write --offset=0x654DC (rd)+1 \x01
chainloader (rd)+1
root ()
title Boot image 2 in boot.wim (Elcomsoft System Recovery)
map --mem /wimpatched (rd)
write --offset=0x654C4 (rd)+1 \x9E\x8A\x02
write --offset=0x654CC (rd)+1 \x20\x6C\x3E\x09
write --offset=0x654D4 (rd)+1 \x98\xE9\x09
write --offset=0x654DC (rd)+1 \x02
chainloader (rd)+1
root ()
title Boot image 3 in boot.wim (Paragon Adaptive Restore P2P/P2V)
map --mem /wimpatched (rd)
write --offset=0x654C4 (rd)+1 \x1C\xF6\x02
write --offset=0x654CC (rd)+1 \x94\x8D\x98\x0A
write --offset=0x654D4 (rd)+1 \xC8\x5A\x0B
write --offset=0x654DC (rd)+1 \x03
chainloader (rd)+1
root ()
title Boot image 4 in boot.wim (StorageCraft Recovery Environment)
map --mem /wimpatched (rd)
write --offset=0x654C4 (rd)+1 \xCE\x4B\x02
write --offset=0x654CC (rd)+1 \xE7\xCB\xF7\x0F
write --offset=0x654D4 (rd)+1 \x90\xC6\x08
write --offset=0x654DC (rd)+1 \x04
chainloader (rd)+1
root ()
Here are my 4 different wim headers and you may notice which values changed;




Now some information about the actual patch.
Here are the parts of bootmgr.exe before and after code was injected.
1. First we must make a call to the place where our code is placed.
Before
- Code: Select all
.text:00420C7A mov [ebp+arg_8], eax
.text:00420C7D test eax, eax
After
- Code: Select all
.text:00420C7A call sub_462200
2. Here we place the code that will patch the wim header in memory. Basically we read 4 dwords starting from 4622F4 (the last one is strictly not necessary, and could be excluded). The trick to differentiate when boot.sdi is read is to compare against bl. This is very lame and prone to errors and should be changed. However it will work as long as the image (not the wim) size is not a multiple of hex 10 or decimal 16 (in bytes). I just wanted this to be a fast Proof of Concept, but may improve this code later on. Note that the location of the wim header in memory can be retrieved from eax+61e74 when eip=420c7a (exact eip does not matter). It may be wise to just stick with one bootmgr for this purpose, as this location may differ for different versions.
Before
- Code: Select all
.rdata:00462200 db 0
.rdata:00462201 db 0
.rdata:00462202 db 0
.rdata:00462203 db 0
and so on (its a code cave)
After
- Code: Select all
.rdata:00462200 sub_462200 proc near ; CODE XREF: sub_420B28+152p
.rdata:00462200 cmp esi, 306000h
.rdata:00462206 jnz short loc_46221B
.rdata:00462208 mov [ebp+10h], eax
.rdata:0046220B test eax, eax
.rdata:0046220D nop
.rdata:0046220E nop
.rdata:0046220F nop
.rdata:00462210 nop
.rdata:00462211 nop
.rdata:00462212 nop
.rdata:00462213 nop
.rdata:00462214 nop
.rdata:00462215 nop
.rdata:00462216 nop
.rdata:00462217 nop
.rdata:00462218 retn 0
.rdata:0046221B ; ---------------------------------------------------------------------------
.rdata:0046221B
.rdata:0046221B loc_46221B: ; CODE XREF: sub_462200+6j
.rdata:0046221B mov edx, ds:dword_4622F4
.rdata:00462221 mov [eax+82B060h], edx
.rdata:00462227 xor edx, edx
.rdata:00462229 mov edx, ds:dword_4622FC
.rdata:0046222F mov [eax+82B068h], edx
.rdata:00462235 xor edx, edx
.rdata:00462237 mov edx, ds:dword_462304
.rdata:0046223D mov [eax+82B070h], edx
.rdata:00462243 xor edx, edx
.rdata:00462245 mov edx, ds:dword_46230C
.rdata:0046224B mov [eax+82B078h], edx
.rdata:00462251 xor edx, edx
.rdata:00462253 mov [ebp+10h], eax
.rdata:00462256 test eax, eax
.rdata:00462258 retn 0
.rdata:00462258 sub_462200 endp
3. This is the place where our values to-be-written-into-wim-header are placed. When mapping bootmgr to rd with grub4dos, you will patch 4 (optionally 3) dwords, to 4622F4, 4622FC, 462304 and 46230C.
Before
- Code: Select all
.rdata:004622F4 db 0
.rdata:004622F5 db 0
.rdata:004622F6 db 0
.rdata:004622F7 db 0
and so on (this is still the same code cave)
After
- Code: Select all
.rdata:004622F4 dword_4622F4 dd 24BCEh ; DATA XREF: sub_462200:loc_46220Er
.rdata:004622F8 db 0
.rdata:004622F9 db 0
.rdata:004622FA db 0
.rdata:004622FB db 0
.rdata:004622FC dword_4622FC dd 0FF7CBE7h ; DATA XREF: sub_462200+1Cr
.rdata:00462300 db 0
.rdata:00462301 db 0
.rdata:00462302 db 0
.rdata:00462303 db 0
.rdata:00462304 dword_462304 dd 8C690h ; DATA XREF: sub_462200+2Ar
.rdata:00462308 db 0
.rdata:00462309 db 0
.rdata:0046230A db 0
.rdata:0046230B db 0
.rdata:0046230C dword_46230C dd 4 ; DATA XREF: sub_462200+38r
The last part in hex view;
- Code: Select all
004622F4 CE 4B 02 00 00 00 00 00 E7 CB F7 0F 00 00 00 00
00462304 90 C6 08 00 00 00 00 00 04 00 00 00 00 00 00 00
As you may see it is actually possible to rewrite the complete header, but of course we only modify the stuff strictly necessary. My custom wim header values are hardcoded in the provided bootmgr, occording to the above, so that it is easier for you to understand where grub4dos is patching it, and to better understand the patch when disassembling it.
I know this is not fool proof, because 2 things can happen which will prevent further booting;
1. The size of the boot.sdi is not 306000h (like my custom one). But if you stick to the original you are safe.
2. The size of the target image is equal to 306000h. But that is just not possible as an nt6 based WinPE cannot be that small!
Note that for those that are using my custom boot.sdi at 300 Kb, http://www.msfn.org/board/topic/145209- ... f-bootsdi/ , it is necessary to patch 5 instructions. Add this to each entry in menu.lst;
- Code: Select all
write --offset=0x653D3 (rd)+1 \xB0\x04
write --offset=0x653F4 (rd)+1 \x00\x57
write --offset=0x65402 (rd)+1 \x00\x57
write --offset=0x65410 (rd)+1 \x00\x57
write --offset=0x6541E (rd)+1 \x00\x57
Have fun!
Joakim Schicht
Original first post
joakim wrote:I was contacted by a user at msfn about a month ago, who wondered if this is possible. Have had it in the back of my mind since then, until I started some serious hacking this evening. The idea is to have several nt6 based PE images inside the same wim, and thus possibly save several hundred megabytes. May be useful local booting, but definetely not for pxe booting. Why not have 5 different images inside the same wim, instead of having 5 different wim files.
I believe it is possible to boot any image inside a wim, but we need to decode the wim header properly. That is not too difficult, I got most of it. Then we need to patch bootmgr too use our chosen offset for image. That can be done by overwriting the register that holds the wim header (after boot.wim is mapped). Specifically this is at esi+0x68 (the interesting offset). I am too tired to figure out the right machine code to write correctly, and keep failing. If anybody is interested and willing to join, then come on.
The actual booting, can proceed with grub4dos mapping bootmgr to the (rd) device and patch it there with the required code. We just need to figure out the right code to overwrite the old offset (esi+0x68) with our own.