Phrozen Timeline

This code snippet demonstrate how Malware authors take advantage of certain Windows API's to detect the presence of Windows Services that might indicate the presence of Virtualization Technologies and/or Sandbox in order to adapt their behavior and escape detection.

Read more...

This technique is often used by Malware to hide their presence on system after execution. The application self-delete after the end of its execution. The best method to archive a such goal is through process injection.

Read more...

ADS (Alternate Data Stream) is a channel often abused by Malware authors to hide files by abusing the property of NTFS File Systems.

It is mainly used to store: additional payloads, collected data or settings.

An ADS file is completely hidden from explorer. In modern version of Windows, you can display ADS files using the command dir /r or through using third part tools.

Read more...

Tiny snippet to know whether or not target process id is running under 32bit or 64bit architecture.

If result is True, target process is running under 64bit architecture.

If result is False, target process is running under 32bit architecture.

// ...

uses Windows, SysUtils;

// ...
type
  TArchitecture = (x86, x64, xUnknown);
// ...

function IsProcessX64(AProcessId : Cardinal) : TArchitecture;
var AProcHandle   : THandle;
    AWow64Process : bool;
begin
  result := xUnknown;
  ///

  {
    If we are not in a 64Bit system then we are for sure in a 32Bit system
  }
  if (TOSVersion.Architecture = arIntelX86) then
    Exit();
  ///

  AProcHandle := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, AProcessId);
  if AProcHandle = 0 then
    Exit;
  try
    isWow64Process(AProcHandle, AWow64Process);
    ///

    if AWow64Process then
      result := x86
    else
      result := x64;
  finally
    CloseHandle(AProcHandle);
  end;
end;
Read more...

This is one of the most famous method to enumerate running process on Windows.

If AFilterSameArch is set to True, only processes running with same architecture as current process will be listed.

{
    Jean-Pierre LESUEUR (@DarkCoderSc)

    Example:

    ...
    var AProcessName    : String;
        AProcessId      : Cardinal;
        AProcessList    : TDictionary<Integer, String>;
    begin
        AProcessList := EnumProcess(True);
        try
            for AProcessId in AProcessList.Keys do begin
                if NOT AProcessList.TryGetValue(AProcessId, AProcessName) then
                    continue;
                ///

                ...
            end;
        finally
            if Assigned(AProcessList) then
            FreeAndNil(AProcessList);
        end;
    end;
}

//...
uses tlhelp32, SysUtils, Windows, Generics.Collections;
//...

function EnumProcess(AFilterSameArch : Boolean = False) : TDictionary<Integer {Process Id}, String {Process Name}>;
var ASnap         : THandle;
    AProcessEntry : TProcessEntry32;
    AProcessName  : String;

    procedure AppendEntry();
    begin
      if AFilterSameArch and ((IsProcessX64(GetCurrentProcessId())) <> (IsProcessX64(AProcessEntry.th32ProcessID))) then
        Exit();
      ///

      result.Add(AProcessEntry.th32ProcessID, AProcessEntry.szExeFile);
    end;

begin
  result := TDictionary<Integer, String>.Create();
  ///

  ASnap := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if ASnap = INVALID_HANDLE_VALUE then
    Exit();
  try
    ZeroMemory(@AProcessEntry, SizeOf(TProcessEntry32));
    ///

    AProcessEntry.dwSize := SizeOf(TProcessEntry32);

    if NOT Process32First(ASnap, AProcessEntry) then
      Exit();

    AppendEntry();

    while True do begin
      ZeroMemory(@AProcessEntry, SizeOf(TProcessEntry32));
      ///

      AProcessEntry.dwSize := SizeOf(TProcessEntry32);

      if NOT Process32Next(ASnap, AProcessEntry) then
        break;

      AppendEntry();
    end;
  finally
    CloseHandle(ASnap);
  end;
end;
Read more...

Tiny delphi unit to get and update debug flag from PEB (Process Environment Block).

This unit was created while working on a friend project called Unprotect (@fr0gger_), https://github.com/fr0gger/unprotect

Indeed, some Malware often check the value of Debug flag to know whether or not they are getting debugged and apply anti debug techniques if this is the case.

Example of implementation can be found there

(*******************************************************************************


  Author:
    ->  Jean-Pierre LESUEUR (@DarkCoderSc)
        https://github.com/DarkCoderSc
        https://gist.github.com/DarkCoderSc
        https://www.phrozen.io/

  License:
    -> MIT


*******************************************************************************)

unit UntPEBDebug;

interface

uses Windows;

const PROCESS_QUERY_LIMITED_INFORMATION = $1000;
      PROCESS_BASIC_INFORMATION         = 0;

// https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess
var _NtQueryInformationProcess : function(
                                            ProcessHandle : THandle;
                                            ProcessInformationClass : DWORD;
                                            ProcessInformation : Pointer;
                                            ProcessInformationLength :
                                            ULONG; ReturnLength : PULONG) : LongInt; stdcall;

    hNTDLL : THandle;


{$IFDEF WIN64}
type
  PProcessBasicInformation = ^TProcessBasicInformation;
  TProcessBasicInformation = record
    ExitStatus         : Int64;
    PebBaseAddress     : Pointer;
    AffinityMask       : Int64;
    BasePriority       : Int64;
    UniqueProcessId    : Int64;
    InheritedUniquePID : Int64;
  end;
{$ELSE}
type
  PProcessBasicInformation = ^TProcessBasicInformation;
  TProcessBasicInformation = record
    ExitStatus         : DWORD;
    PebBaseAddress     : Pointer;
    AffinityMask       : DWORD;
    BasePriority       : DWORD;
    UniqueProcessId    : DWORD;
    InheritedUniquePID : DWORD;
  end;
{$ENDIF}

function GetProcessDebugStatus(AProcessID : Cardinal; var ADebugStatus : boolean) : Boolean;
function SetProcessDebugStatus(AProcessID : Cardinal; ADebugStatus : Boolean) : Boolean;

implementation

{-------------------------------------------------------------------------------
  Open a process and retrieve the point of debug flag from PEB.

  If function succeed, don't forget to call close process handle.
-------------------------------------------------------------------------------}
function GetDebugFlagPointer(AProcessID : Cardinal; var AProcessHandle : THandle) : Pointer;
var PBI     : TProcessBasicInformation;
    ARetLen : Cardinal;
begin
  result := nil;
  ///

  AProcessHandle := 0;

  if NOT Assigned(_NtQueryInformationProcess) then
    Exit();
  ///

  AProcessHandle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_WRITE or PROCESS_VM_READ, false, AProcessID);
  if (AProcessHandle = 0) then
    Exit;

  if _NtQueryInformationProcess(AProcessHandle, PROCESS_BASIC_INFORMATION, @PBI, sizeOf(TProcessBasicInformation), @ARetLen) = ERROR_SUCCESS then
    result := Pointer(NativeUInt(PBI.PebBaseAddress) + (SizeOf(Byte) * 2))
  else
    CloseHandle(AProcessHandle);
end;

{-------------------------------------------------------------------------------
  Retrieve the target process debug status from PEB.

  ADebugStatus = True  : Target process debug flag is set.
  ADebugStatus = False : Target process debug flag is not set.
-------------------------------------------------------------------------------}
function GetProcessDebugStatus(AProcessID : Cardinal; var ADebugStatus : boolean) : Boolean;
var hProcess         : THandle;

    pDebugFlagOffset : Pointer;
    pDebugFlag       : pByte;
    ABytesRead       : SIZE_T;
begin
  result := false;
  ///

  pDebugFlagOffset := GetDebugFlagPointer(AProcessID, hProcess);

  if not Assigned(pDebugFlagOffset) then
    Exit();
  ///
  try
    getMem(pDebugFlag, sizeOf(Byte));
    try
      if NOT ReadProcessMemory(hProcess, pDebugFlagOffset, pDebugFlag, sizeOf(Byte), ABytesRead) then
        Exit;

      ///
      ADebugStatus := (pDebugFlag^ = 1);
    finally
      FreeMem(pDebugFlag);
    end;

    ///
    result := (ABytesRead = SizeOf(Byte));
  finally
    CloseHandle(hProcess);
  end;
end;

{-------------------------------------------------------------------------------
  Update target process debug flag.

  ADebugStatus = True  : Set target process debug flag.
  ADebugStatus = False : Unset target process debug flag.
-------------------------------------------------------------------------------}
function SetProcessDebugStatus(AProcessID : Cardinal; ADebugStatus : Boolean) : Boolean;
var hProcess         : THandle;

    pDebugFlagOffset : Pointer;
    ADebugFlag       : Byte;
    ABytesWritten    : SIZE_T;
begin
  result := false;
  ///

  pDebugFlagOffset := GetDebugFlagPointer(AProcessID, hProcess);

  if not Assigned(pDebugFlagOffset) then
    Exit();
  ///
  try
    if ADebugStatus then
      ADebugFlag := 1
    else
      ADebugFlag := 0;

    if NOT WriteProcessMemory(hProcess, pDebugFlagOffset, @ADebugFlag, SizeOf(Byte), ABytesWritten) then
      Exit;

    ///
    result := (ABytesWritten = SizeOf(Byte));
  finally
    CloseHandle(hProcess);
  end;
end;

initialization
  {
    Load NtQueryInformationProcess from NTDLL.dll
  }
  _NtQueryInformationProcess := nil;

  hNTDLL := LoadLibrary('ntdll.dll');

  if (hNTDLL <> 0) then
    @_NtQueryInformationProcess := GetProcAddress(hNTDLL, 'NtQueryInformationProcess');

finalization
  _NtQueryInformationProcess := nil;

  if (hNTDLL <> 0) then
    FreeLibrary(hNTDLL);


end.
Read more...

You will find below 4 different techniques to close/kill/terminate Windows process in pure WinAPI.

Techniques

  • TerminateProcess() : Classic method.
  • ExitProcess() : via Code Injection (32bit to 32bit ; 64bit to 64bit).
  • Crash Process : Inject code that will crash the process (32bit to 32bit ; 64bit to 64bit).
  • CTRL_CLOSE_EVENT / WM_CLOSE : Send "close" messages to target process windows.

TerminateAProcess() Method

Kill target process id following desired method : tmpAll, tpmTerminateProcess, tpmExitProcess, tpmCrash, tpmMessage

tmpAll attempt to kill process from cleanest way to dirtiest way until it succeed.

Read more...

You will find below an example of how to enumerate process modules using the well known Windows API CreateToolHelp32Snapshot(), I will cover additional methods soon.

You may notice that when using CreateToolHelp32Snapshot(), first result (row) is generally the Image Path of the process owning module. I ignore that row by checking the value of szExePath with owner process image path.

GetProcessName() is compatible since Windows Vista. It is possible to support Windows XP and below but not in this example.

You will find GetProcessName() and alternatives in separated snippets threads.

Read more...

This one possible technique (through QueryFullProcessImageNameW) to get process image path from it id.

This example support Windows Vista to latest Windows version (Actually Windows 10)

I will cover other example progressively and compatible with Windows XP and below.

// Jean-Pierre LESUEUR (@DarkCoderSc)

//...
uses Windows, SysUtils;
//...

function GetProcessName(AProcessID : Cardinal) : String;
var hProc      : THandle;
    ALength    : DWORD;
    hDLL       : THandle;

    QueryFullProcessImageNameW : function(
                                            AProcess: THANDLE;
                                            AFlags: DWORD;
                                            AFileName: PWideChar;
                                            var ASize: DWORD): BOOL; stdcall;

const PROCESS_QUERY_LIMITED_INFORMATION = $00001000;
begin
  result := '';
  ///

  if (TOSVersion.Major < 6) then  
    Exit();
  ///

  QueryFullProcessImageNameW := nil;

  hDLL := LoadLibrary('kernel32.dll');
  if hDLL = 0 then
    Exit();  
  try
    @QueryFullProcessImageNameW := GetProcAddress(hDLL, 'QueryFullProcessImageNameW');
    ///

    if Assigned(QueryFullProcessImageNameW) then begin
      hProc := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, AProcessID);
      if hProc = 0 then exit;
      try
        ALength := (MAX_PATH * 2);

        SetLength(result, ALength);

        if NOT QueryFullProcessImageNameW(hProc, 0, @result[1], ALength) then 
          Exit();

        SetLength(result, ALength); // Get rid of extra junk
      finally
        CloseHandle(hProc);
      end;
    end;
  finally
    FreeLibrary(hDLL);
  end;
end;
Read more...

This unit demonstrate how to enumerate DLL exported functions through PE Header manipulation.

Features

  • Support both 32 and 64bit DLL's.
  • Identify exported function names.
  • Identify exported function ordinal value.
  • Support and resolve forwarded function.
  • Identify export function address and relative address.
Read more...