News:

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

Main Menu

A self-deleting executable

Started by Fabioxds, March 25, 2018, 05:36:31 AM

Previous topic - Next topic

Fabioxds

I've always wondered it there was a way to create a self-deleting exe without relying on anything but on pure code, so I've come up with this:

1 - Use CreateProcess to spawn a suspended copy o rundll32.exe with a duplicated handle of the parent process
2 - Call WriteProcessMemory to inject a string of the path, a custom function and a data structure containing the needed function pointers and parent process handle value into the child process
3 - Create a remote thread then set the initial address to my custom function
4 - My custom function then uses WaitForSingleObject to wait for the parent's exit, then call CloseHandle & DeleteFile

As I'm a MASM noob, I would appreciate suggestions on:

- How to take advantage of more MASM features, ie: less hard-coded values/cleaner code (specially the RemoteThreadProc function)
- Not sure if the DeleteLoop is necessary, but I think there is a possibility for a race condition after WaitForSingleObject returns and I call DeleteFileA, if the system still has open handles to the parent exe file (but in all my tests, even if I don't call CloseHandle inside rundll32.exe, DeleteFile always works)
- Microsoft Security Essentials once detected my compiled exe as a 'potential security risk', maybe I'm doing something suspicious?


.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
RemoteThreadProc proto :DWORD
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

DATA STRUCT
fpWaitSObj dd ?
fpDeleteFile dd ?
fpExitProcess dd ?
fpCloseHandle dd ?
fpSleep dd ?
hParentProcess HANDLE ?
DATA ENDS

.data
processInfo PROCESS_INFORMATION <>
stData DATA <>
startInfo STARTUPINFO <>
szChildProcess db "rundll32.exe",0
szKernel32Dll db "kernel32.dll",0
szWaitForSObj db "WaitForSingleObject",0
szDeleteFile db "DeleteFileA",0
szExitProcess db "ExitProcess",0
szCloseHandle db "CloseHandle",0
szSleep db "Sleep",0
szMsg db "Press OK to exit and (hopefully) self-delete.",0

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
szAppPath db 512 dup(?)
hCurrentProcess HANDLE ?
hModule HANDLE ?
hRemoteThread HANDLE ?
PathLen dd ?
pRemoteFunc dd ?
dwBaseAddress dd ?
dwTotalWritten dd ?
dwFuncSize dd ?
dwOldProtect dd ?

.code
start:
    invoke GetModuleHandle, NULL
    mov    hInstance,eax
    invoke GetCommandLine
    mov CommandLine,eax
    invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
    invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
invoke GetModuleFileNameA, 0, addr szAppPath, 512

invoke GetStartupInfo,ADDR startInfo
    invoke CreateProcess,NULL,ADDR szChildProcess,NULL,NULL,TRUE, CREATE_SUSPENDED,NULL,NULL,ADDR startInfo,ADDR processInfo

    .if eax!=NULL
invoke GetModuleHandle,ADDR szKernel32Dll
mov hModule, eax

invoke GetProcAddress,hModule,ADDR szWaitForSObj
push eax
pop stData.fpWaitSObj
invoke GetProcAddress,hModule,ADDR szDeleteFile
push eax
pop stData.fpDeleteFile
invoke GetProcAddress,hModule,ADDR szExitProcess
push eax
pop stData.fpExitProcess
invoke GetProcAddress,hModule,ADDR szCloseHandle
push eax
pop stData.fpCloseHandle
invoke GetProcAddress,hModule,ADDR szSleep
push eax
pop stData.fpSleep

invoke GetCurrentProcess
mov hCurrentProcess, eax
invoke DuplicateHandle,hCurrentProcess, hCurrentProcess, processInfo.hProcess, ADDR stData.hParentProcess, 0, FALSE, DUPLICATE_SAME_ACCESS

invoke VirtualAllocEx, processInfo.hProcess, 0, 8192, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE
.if eax == NULL
jmp @quit
.endif
mov pRemoteFunc, eax
mov dwBaseAddress, eax

invoke lstrlen, ADDR szAppPath
inc eax
mov PathLen, eax
add dwBaseAddress, 4096
invoke WriteProcessMemory, processInfo.hProcess, dwBaseAddress, ADDR szAppPath, PathLen, ADDR dwTotalWritten

sub dwBaseAddress, 4096
invoke WriteProcessMemory, processInfo.hProcess, dwBaseAddress, ADDR stData, SIZEOF stData, ADDR dwTotalWritten

mov eax, (getFuncSizeLabel - offset RemoteThreadProc)
mov dwFuncSize, eax
add dwBaseAddress, SIZEOF stData
invoke WriteProcessMemory, processInfo.hProcess, dwBaseAddress, ADDR RemoteThreadProc, dwFuncSize, ADDR dwTotalWritten
sub dwBaseAddress, SIZEOF stData

invoke VirtualProtectEx, processInfo.hProcess, dwBaseAddress, 4096, PAGE_EXECUTE_READ, ADDR dwOldProtect
add dwBaseAddress, 4096
invoke VirtualProtectEx, processInfo.hProcess, dwBaseAddress, 4096, PAGE_READONLY, ADDR dwOldProtect
sub dwBaseAddress, 4096

add pRemoteFunc, SIZEOF stData
invoke CreateRemoteThread, processInfo.hProcess, 0, 0, pRemoteFunc, dwBaseAddress, CREATE_SUSPENDED, 0
.if eax != NULL
mov hRemoteThread, eax
invoke ResumeThread, hRemoteThread
invoke CloseHandle, hRemoteThread
invoke MessageBox, 0, ADDR szMsg, ADDR szMsg, MB_OK or MB_ICONEXCLAMATION
.endif
invoke CloseHandle, processInfo.hProcess
invoke CloseHandle, processInfo.hThread
.endif

@quit:
ret
WinMain endp

RemoteThreadProc proc lpParameter:DWORD
LOCAL basePointer : DWORD
mov eax, lpParameter
mov basePointer, eax

mov edx, [eax + 14h] ; parent process handle
push INFINITE
push edx
mov edx, [eax]
call edx ; WaitForSingleObject

.if eax == WAIT_OBJECT_0
mov eax, basePointer
mov edx, [eax + 14h]
push edx
mov edx, [eax + 12d]
call edx ; CloseHandle

DelFileLoop:
mov eax, basePointer
add eax, 4096
push eax                                  ; string address
sub eax, 4096                                  ; back to the base address; this seems a ugly hack...
mov edx, [eax + 4h]
call edx                                          ; DeleteFileA
.if eax == 0                                       ; DeleteFileA failed
mov eax, basePointer
mov edx, [eax + 10h]                   ; Sleep
push 512
call edx
jmp DelFileLoop
.endif
.endif

mov eax, basePointer
push 0
mov edx, [eax + 8h]                               ; ExitProcess
call edx

ret
RemoteThreadProc endp
getFuncSizeLabel:
mov edi, edi

end start

Vortex

Hello Fabioxds,

QuoteMicrosoft Security Essentials once detected my compiled exe as a 'potential security risk', maybe I'm doing something suspicious?

You would like to check Jotti's report :

https://virusscan.jotti.org/en-US/filescanjob/kcnf6e3knk

WriteProcessMemory and "injection" are enough to trigger the AV engines. They can be intepreted as "suspicious"

The method presented by aw27 is safer :

http://masm32.com/board/index.php?topic=6713.0