YADI - Yet another DLL injector
YADI
Yet another DLL injector - by Harava
https://i59.tinypic.com/28hndio.png
I had the need for a dll injector that injects my dll before the target application has a chance to do anything. So I created YADI.
YADI utilizes the undocumented winapi functions NtSuspendProcess & NtResumeProcess to suspend the target before injection.
EDIT: So I did work on it some more: I added the ability to inject into running processes and a autoinject feature. Also I fixed some code for the window. I was passing BS_PUSHBUTTON to the edits and not the buttons. ( Maybe I should smoke less )
I thought some of you might want to take a look at the source code, so here it is:
GVARS.h:
Code:
// DEFINES FOR THE WINDOW
#define DLL_NAME_EDIT (WM_APP + 101)
#define TARGET_NAME_EDIT (WM_APP + 102)
#define OPEN_TARGET_BTN (WM_APP + 103)
#define OPEN_DLL_BTN (WM_APP + 104)
#define INJECT_BTN (WM_APP + 105)
#define INJECTNS_BTN (WM_APP + 115)
#define AUTO_CHK (WM_APP + 113)
#define STATUS_EDIT (WM_APP + 106)
#define YADI_WIN_X 300
#define YADI_WIN_Y 320
// TYPEDEFS AND HANDLES FOR DYNAMIC LOADING
HMODULE hNTDLL = NULL;
HMODULE hComdlg32 = NULL;
typedef BOOL (WINAPI *GOFNA)( LPOPENFILENAMEA ); // GetOpenFileNameA
GOFNA pGOFNA;
typedef LONG (NTAPI *NtSP)( HANDLE ProcessHandle );// NtSuspendProcess
typedef LONG (NTAPI *NtRP)( HANDLE ProcessHandle );// NtResumeProcess
NtSP pNtSP;
NtRP pNtRP;
// WINDOW ITEM DECLARATIONS:
HWND hwndDllEdit;
HWND hwndTargetEdit;
HWND hwndStatusEdit;
HWND hwndAutoCheck;
HWND hwndTargetBtn;
HWND hwndDllBtn;
HWND hwndInjectBtn;
HWND hwndInjectNSBtn;
HWND YADIWIN;
// VARIABLES FOR INJECTION
bool DllSet = false;
bool TargetSet = false;
bool StartedProcessRunning = false;
char DllPath[MAX_PATH];
char TargetPath[MAX_PATH];
OPENFILENAMEA ofnDll;
OPENFILENAMEA ofnTarget;
PROCESS_INFORMATION pi;
STARTUPINFO si;
HANDLE hAutoInject;
DWORD dwLastPID;
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); // WindowProc
char szClassName[ ] = "YADIwclass"; // WndClassName
FUNCS.h:
Code:
#ifndef FUNCS_H_INCLUDED
#define FUNCS_H_INCLUDED
#include <string.h>
#include <Psapi.h>
#pragma comment(lib, "Psapi.lib")
#endif // FUNCS_H_INCLUDED
/* **************************************** */
/* START WAITER */
/* **************************************** */
DWORD WINAPI WaitThread( LPVOID lpParam )
{
HANDLE hProcess = (HANDLE)lpParam;
WaitForSingleObject(hProcess, INFINITE);
StartedProcessRunning = false;
CloseHandle(hProcess);
return 0;
}
/* **************************************** */
/* START & INJECT */
/* **************************************** */
bool Inject()
{
if(!DllSet || !TargetSet)
return false;
if(StartedProcessRunning)
{
return false;
}
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
CreateProcess(NULL, TargetPath, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
if(pi.hProcess == NULL)
{
MessageBoxA(NULL, "Unable to start target!", "Error", MB_OK);
return false;
}
pNtSP(pi.hProcess); // Suspend the process
LPVOID LoadLibAddr = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
LPVOID RemoteMem = VirtualAllocEx(pi.hProcess, NULL, strlen(DllPath), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess, RemoteMem, DllPath, strlen(DllPath), NULL);
if(CreateRemoteThread(pi.hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddr, RemoteMem, 0, NULL)!=NULL) // Create remote thread to load the dll
{
StartedProcessRunning = true;
pNtRP(pi.hProcess); // SUCCESS! Resume process
CreateThread(NULL, NULL, WaitThread, (LPVOID)pi.hProcess, NULL, NULL);
return true;
}
pNtRP(pi.hProcess); // failed... Resume process
CloseHandle(pi.hProcess);
return false;
}
/* **************************************** */
/* LOAD DYNAMIC */
/* **************************************** */
void LoadDynamic()
{
hNTDLL = GetModuleHandleA("ntdll");
if(hNTDLL == NULL)
hNTDLL = LoadLibraryA("ntdll");
hComdlg32 = GetModuleHandleA("Comdlg32");
if(hComdlg32 == NULL)
hComdlg32 = LoadLibraryA("Comdlg32");
if(hNTDLL == NULL || hComdlg32 == NULL)
{
MessageBoxA(NULL, "Dynamic load of NTDLL or Comdlg32 failed!", "Error", MB_OK);
ExitProcess(-1);
}
pGOFNA = (GOFNA)GetProcAddress(hComdlg32, "GetOpenFileNameA");
pNtRP = (NtRP)GetProcAddress(hNTDLL, "NtResumeProcess");
pNtSP = (NtSP)GetProcAddress(hNTDLL, "NtSuspendProcess");
if(pGOFNA == NULL || pNtRP == NULL || pNtSP == NULL)
{
MessageBoxA(NULL, "Dynamic load of NTDLL & Comdlg32 functions failed!", "Error", MB_OK);
ExitProcess(-1);
}
}
bool CheckAndInjectProcess( DWORD processID )
{
char szProcessName[MAX_PATH] = "<unknown>";
HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, // Less access would be fine, feel free to fix this
FALSE, processID );
if (NULL != hProcess )
{
HMODULE hMod;
DWORD cbNeeded;
if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod),
&cbNeeded) )
{
GetModuleBaseName( hProcess, hMod, szProcessName,
sizeof(szProcessName)/sizeof(char) );
}
CloseHandle( hMod );
}
char * pch;
pch=strrchr(TargetPath,'\\');
if(pch != NULL)
{
if(strcmp(szProcessName, (pch+1)) == 0)
{
if(dwLastPID != processID)
{
LPVOID LoadLibAddr = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
LPVOID RemoteMem = VirtualAllocEx(hProcess, NULL, strlen(DllPath), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, RemoteMem, DllPath, strlen(DllPath), NULL);
if(CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddr, RemoteMem, 0, NULL)!=NULL) // Create remote thread to load the dll
{
dwLastPID = processID;
return true;
}
}
}
}
CloseHandle( hProcess );
return false;
}
bool SearchInjectAll()
{
if(!DllSet || !TargetSet)
return false;
DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i;
if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
{
return false;
}
cProcesses = cbNeeded / sizeof(DWORD);
for ( i = 0; i < cProcesses; i++ )
{
if( aProcesses[i] != 0 )
{
if(CheckAndInjectProcess( aProcesses[i] ))
return true;
}
}
return false;
}
DWORD WINAPI AutoInjectThread ( LPVOID lpParam )
{
while(1)
{
if(!StartedProcessRunning)
{
if(SearchInjectAll())
SetDlgItemTextA(YADIWIN, STATUS_EDIT, "Status: Auto-Inject succesful!");
}
Sleep(50);
}
return 0;
}
YADI.cpp:
Code:
#include <windows.h>
#include "GVARS.h"
#include "FUNCS.h"
#pragma comment(lib, "Kernel32.lib")
#pragma comment(lib, "User32.lib")
/* **************************************************************************
YADI - Yet another DLL injector
by Harava
YADI is designed to inject DLL's before the target
application has a chance to do anything. YADI uses
the undocumented NtDll functions to suspend the
target application once it has started, and then
resumes it once the dll has been succesfully injected.
************************************************************************** */
/* **************************************** */
/* WinMain */
/* **************************************** */
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
LoadDynamic();
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
wincl.hIcon = LoadIconA(NULL, IDI_EXCLAMATION);
wincl.hIconSm = LoadIconA(NULL, IDI_EXCLAMATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
wincl.hbrBackground = (HBRUSH) CreateSolidBrush(RGB(100, 150, 10));
if (!RegisterClassEx (&wincl))
return 0;
hwnd = CreateWindowEx (
WS_EX_CLIENTEDGE, /* Extended possibilites for variation */
szClassName, /* Classname */
"YADI", /* Title Text */
WS_DLGFRAME | WS_EX_PALETTEWINDOW | WS_SYSMENU, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
YADI_WIN_X, /* The programs width */
YADI_WIN_Y, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
ShowWindow (hwnd, SW_SHOW);
while (GetMessage (&messages, NULL, 0, 0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
/* **************************************** */
/* WindProc */
/* **************************************** */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_CREATE:
hwndDllBtn = CreateWindowExA(NULL, "BUTTON", "Open DLL", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 10, 270, 25, hwnd, (HMENU)OPEN_DLL_BTN, GetModuleHandleA(NULL), NULL);
hwndDllEdit = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE,
10, 45, 270, 25, hwnd, (HMENU)DLL_NAME_EDIT, GetModuleHandleA(NULL), NULL);
hwndTargetBtn = CreateWindowExA(NULL, "BUTTON", "Open target", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 80, 270, 25, hwnd, (HMENU)OPEN_TARGET_BTN, GetModuleHandleA(NULL), NULL);
hwndTargetEdit = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE,
10, 115, 270, 25, hwnd, (HMENU)TARGET_NAME_EDIT, GetModuleHandleA(NULL), NULL);
hwndInjectBtn = CreateWindowExA(NULL, "BUTTON", "Start and inject!", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 150, 270, 25, hwnd, (HMENU)INJECT_BTN, GetModuleHandleA(NULL), NULL);
hwndInjectNSBtn = CreateWindowExA(NULL, "BUTTON", "Inject!", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 185, 270, 25, hwnd, (HMENU)INJECTNS_BTN, GetModuleHandleA(NULL), NULL);
hwndAutoCheck = CreateWindowExA(NULL, "BUTTON", "Auto-inject", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
10, 220, 270, 25, hwnd, (HMENU)AUTO_CHK, GetModuleHandleA(NULL), NULL);
hwndStatusEdit = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "Status: Idle", WS_CHILD | WS_VISIBLE,
10, 255, 270, 25, hwnd, (HMENU)STATUS_EDIT, GetModuleHandleA(NULL), NULL);
EnableWindow(hwndDllEdit, false);
EnableWindow(hwndTargetEdit, false);
EnableWindow(hwndStatusEdit, false);
YADIWIN = hwnd;
break;
case WM_COMMAND:
switch(wParam)
{
case OPEN_DLL_BTN:
ZeroMemory(&ofnDll, sizeof(OPENFILENAMEA));
ZeroMemory(DllPath, sizeof(DllPath));
ofnDll.lStructSize = sizeof(OPENFILENAMEA);
ofnDll.hwndOwner = hwnd;
ofnDll.lpstrFilter = "DLL files\0*.DLL";
ofnDll.lpstrFile = DllPath;
ofnDll.nMaxFile = sizeof(DllPath);
ofnDll.lpstrTitle = "Open dll.";
ofnDll.Flags = OFN_FILEMUSTEXIST;
if(pGOFNA(&ofnDll))
{
DllSet = true;
SetDlgItemTextA(hwnd, DLL_NAME_EDIT, DllPath);
}
else
{
DllSet = false;
SetDlgItemTextA(hwnd, DLL_NAME_EDIT, "");
}
break;
case OPEN_TARGET_BTN:
ZeroMemory(&ofnTarget, sizeof(OPENFILENAMEA));
ZeroMemory(TargetPath, sizeof(TargetPath));
ofnTarget.lStructSize = sizeof(OPENFILENAMEA);
ofnTarget.hwndOwner = hwnd;
ofnTarget.lpstrFilter = "exe files\0*.EXE";
ofnTarget.lpstrFile = TargetPath;
ofnTarget.nMaxFile = sizeof(TargetPath);
ofnTarget.lpstrTitle = "Open target";
ofnTarget.Flags = OFN_FILEMUSTEXIST;
if(pGOFNA(&ofnTarget))
{
TargetSet = true;
SetDlgItemTextA(hwnd, TARGET_NAME_EDIT, TargetPath);
}
else
{
TargetSet = false;
SetDlgItemTextA(hwnd, TARGET_NAME_EDIT, "");
}
break;
case INJECT_BTN:
if(Inject())
{
SetDlgItemTextA(hwnd, STATUS_EDIT, "Status: Injected!");
}
else
{
SetDlgItemTextA(hwnd, STATUS_EDIT, "Status: Injection failed!");
}
break;
case INJECTNS_BTN:
if(SearchInjectAll())
{
SetDlgItemTextA(hwnd, STATUS_EDIT, "Status: Injected!");
}
else
{
SetDlgItemTextA(hwnd, STATUS_EDIT, "Status: Injection failed!");
}
break;
case AUTO_CHK:
if(HIWORD(wParam)==BN_CLICKED)
{
if(IsDlgButtonChecked(hwnd, AUTO_CHK))
{
hAutoInject = CreateThread(NULL, NULL, AutoInjectThread, NULL, NULL, NULL);
}
else
{
TerminateThread(hAutoInject, 0);
CloseHandle(hAutoInject);
}
}
break;
}
break;
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
If you have any questions / suggestions, please tell me!