News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Quite weird situation inside PE protector...

Started by PsYcHoCoDe, November 01, 2012, 09:53:35 PM

Previous topic - Next topic

PsYcHoCoDe

hey, guys, being working on a PE protector... yet, i got a quite weird situation(and i still can't get how it's possible @all): the code's goes like this -> opens (maps it) the file, encrypt it, write to disk, map it AGAIN to restore the original EntryPoint, replace the first X bytes after the original entry point(storing them inside the loader inside a new section to be restored on runtime), calculate the PE's checksum, write it again on disk...

the code, that does that, works actually perfectly... here comes the surprise -> the file, written onto disk the second time, contain ALL modifications made, EXCEPT the stub for transition to loader's code... (while it was just correctly generated inside the memory, checked it out many times under immunity debugger)... anyone's got any idea about that?! dev. platform is win xp based...

qWord

MREAL macros - when you need floating point arithmetic while assembling!

PsYcHoCoDe

ye, got that, the memory mapping is done, using GlobalAlloc... what additional info do you need, mate?

PS: a binary of the project, an encrypted binary file, etc?

Tedd

First guess: you're replacing the file containing the stub when you re-open it; this depends on the flags you give to CreateFile.

As qWord amusingly pointed out, we need a little more to work with otherwise we're just guessing.
Try to make a smaller example that still has the problem - this is actually a good technique for finding the problem in itself. If you're still having trouble, attach a working code sample so we can look and optionally build in order to test.
Potato2

PsYcHoCoDe

qWord, yeah, i know it's fair to give some more info actually ;) so here it goes...

situation goes so: first, this is the second file mapping (the point where i actually call the procedure to replace these bytes and do all about it:

      ; GENERATE PE CHECKSUM...
      invoke CreateFile, szFname, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL+FILE_FLAG_SEQUENTIAL_SCAN, 0
      mov hFile, eax
      invoke GetFileTime, hFile, addr fCRTime, addr fACTime, addr fWRTime
      invoke GetFileSize, hFile, 0
      mov dwOutPutSize, eax
      invoke GlobalAlloc, GPTR, dwOutPutSize
      mov pMem, eax
      invoke ReadFile, hFile, pMem, dwOutPutSize, addr dwBytesWritten, 0
      invoke CloseHandle, hFile
      invoke StealBytes, pMem, OEP, PEP ; TODO!
      mov eax, pMem


... and these are the procedures, that are related to the replacement  of code itself:

StolenCodeReplacementProc PROC
    db 068h ; push
SIZEOF_DATA_BEFORE_PEP_VA equ ($-offset StolenCodeReplacementProc)
    new_ep dd 0
    jmp @after_struc
    entrypoints db SIZEOF_EP_STRUC dup(0)
@after_struc:
    ret
StolenCodeReplacementProc ENDP
SIZEOF_STOLEN_BYTES equ ($-offset StolenCodeReplacementProc)

SB_DATA STRUC
    OEP_RVA dd ?
    OEP_VA dd ?
    PEP_RVA dd ?
    PEP_VA dd ?
SB_DATA ENDS
sbData SB_DATA <0>

StealBytes PROC uses ebx ecx edx esi edi ptrMem:DWORD, dOEP:DWORD, dPEP:DWORD
LOCAL ptrFirstSec:DWORD
LOCAL ptrNtHeader:DWORD
LOCAL ptrTextSec:DWORD
LOCAL ptrPackSec:DWORD
LOCAL rawOEPOffset:DWORD
LOCAL rawPEPOffset:DWORD
LOCAL ptrStorageArea:DWORD
LOCAL ptrOEP:DWORD
LOCAL ptrPEP:DWORD
;int 3
    mov eax, dOEP
    mov sbData.OEP_RVA, eax
    mov eax, dPEP
    mov sbData.PEP_RVA, eax
    mov ebx, ptrMem
    add ebx, [ebx+03Ch]
ASSUME EBX:PTR IMAGE_NT_HEADERS
    mov edx, ebx
    add edx, sizeof IMAGE_NT_HEADERS
    mov ptrFirstSec, edx
    mov ptrNtHeader, ebx
ASSUME EDX:PTR IMAGE_SECTION_HEADER
@sec_lpy:
    mov eax, [edx].VirtualAddress
    cmp sbData.OEP_RVA, eax
    jl @no_text_section
    add eax, [edx].Misc.VirtualSize
    cmp sbData.OEP_RVA, eax
    jg @no_text_section
        mov eax, ptrMem
        add eax, [edx].PointerToRawData
        mov ptrTextSec, eax
        mov eax, sbData.OEP_RVA
        sub eax, [edx].VirtualAddress
        mov rawOEPOffset, eax
        add eax, ptrMem
        mov ptrOEP, eax
@no_text_section:
    mov eax, [edx].VirtualAddress
    cmp sbData.PEP_RVA, eax
    jl @no_packer_section
    add eax, [edx].Misc.VirtualSize
    cmp sbData.PEP_RVA, eax
    jg @no_packer_section
        mov eax, ptrMem
        add eax, [edx].PointerToRawData
        mov ptrPackSec, eax
@no_packer_section:
    add edx, sizeof IMAGE_SECTION_HEADER
    cmp dword ptr [edx], 0
    jz @out_of_lpy
    jmp @sec_lpy
@out_of_lpy:
    mov edi, ptrPackSec
    add edi, BACKUP_AREA_DISTANCE
    mov ptrStorageArea, edi
    mov ecx, SIZEOF_STOLEN_BYTES
    mov esi, ptrOEP
    rep movsb ; injecting original data inside loader...
        mov eax, [ebx].OptionalHeader.ImageBase
        add eax, sbData.PEP_RVA
        mov sbData.PEP_VA, eax ; calculating VA of loader...
        push eax ; PEP VA, stack operation!
    lea esi, StolenCodeReplacementProc
    mov edi, ptrOEP
    mov ecx, SIZEOF_STOLEN_BYTES
    rep movsb ; copying our stub code to OEP...
        pop eax ; PEP VA, stack operation!
        mov edi, ptrOEP
        add edi, SIZEOF_DATA_BEFORE_PEP_VA
        stosd ; injecting VA of loader
        mov eax, sbData.OEP_RVA
        mov [ebx].OptionalHeader.AddressOfEntryPoint, eax
    ret
StealBytes ENDP
ASSUME EBX:NOTHING
ASSUME EDX:NOTHING


it's work in progress, so don't be too harsh about the current quality of the code, please, i know it's got quite more work onto that piece of code  :t

qWord

You are talking about mapping a file, but I can't see it. Also, you told us that the problems occurs when written back to disk, but your snippets doesn't contain any code that does that.
Regardless that, I'm not sure if such topics can be discussed here...
MREAL macros - when you need floating point arithmetic while assembling!

Tedd

Is this a complete working example that exhibits the problem? I don't see where you write to the file.

Also, file-mapping is not the same thing as loading a file into memory - don't say one when you mean the other (they have different implications.)
Potato2

PsYcHoCoDe

yeah, did not expressed myself properly, that's correct, it's being loaded into memory... sorry about that...  :redface:

here comes the code snippet that write's the file to disk, after the correct PE checksum is calculated too (which code i intentionally left off the snippet), as it's fully working anyway...

      invoke CreateFile, szFname, GENERIC_READ+GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL+FILE_FLAG_SEQUENTIAL_SCAN, 0
      mov hFile, eax
      invoke WriteFile, hFile, pMem, dwOutPutSize, addr dwBytesWritten, 0
      invoke SetFileTime, hFile, addr fCRTime, addr fACTime, addr fWRTime
      invoke CloseHandle, hFile
      invoke GlobalFree, pMem
     
      invoke wsprintf, addr szDone, addr fmtDone, ebx
      invoke SetWindowText, hDlg, addr szDone
     
@@Exit:
ret


P.S:
QuoteRegardless that, I'm not sure if such topics can be discussed here...
-> about that, well, this isn't a viral code or something, it's really is a pe protector, so i don't really see nothing wrong about that?  :icon_eek:

Tedd

Quote from: Tedd on November 03, 2012, 09:02:04 AM
First guess: you're replacing the file containing the stub when you re-open it; this depends on the flags you give to CreateFile.

Quote from: PsYcHoCoDe on November 05, 2012, 02:56:34 AM
invoke CreateFile, szFname, GENERIC_READ+GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL+FILE_FLAG_SEQUENTIAL_SCAN, 0
Potato2

PsYcHoCoDe

i use create always, just in case someone or something has deleted the file after i read it to mem and closed it, while i was still working with the inmem data... and while i'm reading in memory(using OPEN_EXISTING)/writing to the disk the COMPLETE file content (by file size), it shouldn't be a problem, i believe? or maybe not? :dazzled:

Tedd

If you've already written to the file and then open with CREATE_ALWAYS, the new file will replace the old one, so those contents will be erased. If you're writing full data (including the stub) to the file again anyway, why bother writing it the first time just to replace it again?
Potato2

PsYcHoCoDe

QuoteIf you're writing full data (including the stub) to the file again anyway, why bother writing it the first time just to replace it again?

i know, that it sound's stupid, but is kind of a workaround, i had to do, related to the proper calculation of the PE checksum field value...  this is the only reason for having to read/write twice :(

qWord

Well, you can set the Checksum to zero for common applications and DLLs  (or do you want to modify System files?).
MREAL macros - when you need floating point arithmetic while assembling!

PsYcHoCoDe

@qWord: hell, no, i don't need to modify system files @all, this is totally legit app, as i mentioned, dude ;) i just wn't to support services' encryption and some day, eventually, drivers... :t

P.S.: my intentions are totally legal... but no one's being born 'educated', you know... so NO, i don't need to modify 'protected system files', or something like that... i just aim to do something real and nice... that's all about that... and still ain't got idea about how's this issue possible to happen, can't get how it's possible, that only the stub code's missing, while every other mod is where it's actually supposed to be in there...  :dazzled:

PsYcHoCoDe

    lea esi, StolenCodeReplacementProc
    mov edi, ptrOEP
    mov ecx, SIZEOF_STOLEN_BYTES
    rep movsb ; copying our stub code to OEP...
        pop eax ; PEP VA, stack operation!
        mov edi, ptrOEP
        add edi, SIZEOF_DATA_BEFORE_PEP_VA
        stosd ; injecting VA of loader
        mov eax, sbData.OEP_RVA
        mov [ebx].OptionalHeader.AddressOfEntryPoint, eax
    ret

anything else works flawlessly even, but this snippet of code is the writing of the new "Go To LOADER's EP" and replace the original code at
OEP with the stub... that ALSO works flawlessly under immunity dbgr(traced it step by step countless number of times, and it also does the job correctly!)... BUT onto disk, this is the only modification of code, that's the ONLY part of modification's, that are actually MISSING...

P.S.:
QuoteWell, you can set the Checksum to zero for common applications and DLLs  (or do you want to modify System files?).
i aim for support to whatever windows "executable" is possible to stumble upon... i just hate when someone report's me i.e. -> hey, dude, this thing "ain't working", u know what i'm talkin' about ;)