Jump to content
Nytro

Code Injections [beginner and advanced]

Recommended Posts

Posted

[h=1]Code Injections [beginner and advanced][/h]Author:

[h=3]RosDevil[/h]

This tutorial is for every level, from beginners to advanced (so to review some aspects or istructions)

I will use as much as i can C++ in this tutorial.

We're going through all kinds of injection.

Before any type of injection we need to get the right privileges, SE_DEBUG_NAME, this is the function to get it:


int privileges(){
HANDLE Token;
TOKEN_PRIVILEGES tp;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&Token))
{
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(Token, 0, &tp, sizeof(tp), NULL, NULL)==0){
return 1; //FAIL
}else{
return 0; //SUCCESS
}
}
return 1;
}

after we need the PID of the target application, it can be got so:


DWORD getPid(string procName){
HANDLE hsnap;
PROCESSENTRY32 pt;
hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
pt.dwSize = sizeof(PROCESSENTRY32);
do{
if(!strcmp(pt.szExeFile, procName.c_str())){
DWORD pid = pt.th32ProcessID;
CloseHandle(hsnap);
return pid;
}
} while(Process32Next(hsnap, &pt));
CloseHandle(hsnap);
return 0;
}

now let's get started with injections:

1) Codecave Injection with CreateRemoteThread()

This method has been treated a lot on internet so i won't go through the code step by step, if you want to see the documented functions go to msdn.

steps:

- Open the target Process through the PID (Api used: OpenProcess())

- Allocate space in the remote process for our function and parameters (Api used: VirtualAllocEx())

- Write our function and parameters in the remote process (Api used: WriteProcessMemory())

- Execute the remote code and optionally free the remote memory (Api used: CreateRemoteThread() and VirtualFree())


#include <windows.h>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include "ntdef.h"
#include <tlhelp32.h>

typedef int (WINAPI* MsgBoxParam)(HWND, LPCSTR, LPCSTR, UINT);
using namespace std;

struct PARAMETERS{
DWORD MessageBoxInj;
char text[50];
char caption[25];
int buttons;
// HWND handle;
};

DWORD getPid(string procName);
int privileges();
DWORD myFunc(PARAMETERS * myparam);
DWORD Useless();

int main()
{
privileges();

DWORD pid = getPid("notepad.exe");
if (pid==0) return 1; //error

HANDLE p;
p = OpenProcess(PROCESS_ALL_ACCESS,false,pid);
if (p==NULL) return 1; //error

char * mytext = "Hello by CodeCave!";
char * mycaption = "Injection result";

PARAMETERS data; //let's fill in a PARAMETERS struct
HMODULE user32 = LoadLibrary("User32.dll");
data.MessageBoxInj = (DWORD)GetProcAddress(user32, "MessageBoxA");
strcpy(data.text, mytext);
strcpy(data.caption, mycaption);
data.buttons = MB_OKCANCEL | MB_ICONQUESTION;


DWORD size_myFunc = (PBYTE)Useless - (PBYTE)myFunc; //this gets myFunc's size


//--------now we are ready to inject


LPVOID MyFuncAddress = VirtualAllocEx(p, NULL, size_myFunc, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);

WriteProcessMemory(p, MyFuncAddress, (void*)myFunc,size_myFunc, NULL);


LPVOID DataAddress = VirtualAllocEx(p,NULL,sizeof(PARAMETERS),MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);

WriteProcessMemory(p, DataAddress, &data, sizeof(PARAMETERS), NULL);

HANDLE thread = CreateRemoteThread(p, NULL, 0, (LPTHREAD_START_ROUTINE)MyFuncAddress, DataAddress, 0, NULL);

if (thread!=0){
//injection completed, not we can wait it to end and free the memory
WaitForSingleObject(thread, INFINITE); //this waits untill thread thread has finished
VirtualFree(MyFuncAddress, 0, MEM_RELEASE); //free myFunc memory
VirtualFree(DataAddress, 0, MEM_RELEASE); //free data memory
CloseHandle(thread);
CloseHandle(p); //don't wait for the thread to finish, just close the handle to the process
cout<<"Injection completed!"<<endl;
}else{
cout<<"Error!"<<endl;
}


system("PAUSE");
return EXIT_SUCCESS;
}

DWORD getPid(string procName){
HANDLE hsnap;
PROCESSENTRY32 pt;
hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
pt.dwSize = sizeof(PROCESSENTRY32);
do{
if(pt.szExeFile == procName){
DWORD pid = pt.th32ProcessID;
CloseHandle(hsnap);
return pid;
}
} while(Process32Next(hsnap, &pt));
CloseHandle(hsnap);
return 0;
}

DWORD myFunc(PARAMETERS * myparam){
MsgBoxParam MsgBox = (MsgBoxParam)myparam->MessageBoxInj;
int result = MsgBox(0, myparam->text, myparam->caption, myparam->buttons);
switch(result){
case IDOK:
//your code
break;
case IDCANCEL:
//your code
break;
}
return 0;
}

DWORD Useless(){
return 0;
}

//this function is needed to get some extra privileges so your code will be able to work without conflicts with the system
int privileges(){
HANDLE Token;
TOKEN_PRIVILEGES tp;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&Token))
{
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(Token, 0, &tp, sizeof(tp), NULL, NULL)==0){
return 1; //FAIL
}else{
return 0; //SUCCESS
}
}
return 1;
}

This code shows that we cannot pass more than 1 parameter to CreateRemoteThread so we need to create a struct (PARAMETERS) and pass it to the remote function

I did a tutorial in past for this, check out:

http://www.rohitab.c...ion-tutorial-c/

NOTE FOR VISTA/WIN7

CreateRemoteThread() for windows Vista and Windows 7 isn't working because of boundaries, the solution is the undocumented function NtCreateThreadEx(), we can get it from ntdll.dll, and replace CreateRemoteThread() with it in the above code (and remember to adjust the parameters)


HANDLE NtCreateThreadEx(HANDLE process, LPTHREAD_START_ROUTINE Start, LPVOID lpParameter);

typedef NTSTATUS (WINAPI *LPFUN_NtCreateThreadEx)
(
OUT PHANDLE hThread,
IN ACCESS_MASK DesiredAccess,
IN LPVOID ObjectAttributes,
IN HANDLE ProcessHandle,
IN LPTHREAD_START_ROUTINE lpStartAddress,
IN LPVOID lpParameter,
IN BOOL CreateSuspended,
IN DWORD StackZeroBits,
IN DWORD SizeOfStackCommit,
IN DWORD SizeOfStackReserve,
OUT LPVOID lpBytesBuffer
);

struct NtCreateThreadExBuffer
{
ULONG Size;
ULONG Unknown1;
ULONG Unknown2;
PULONG Unknown3;
ULONG Unknown4;
ULONG Unknown5;
ULONG Unknown6;
PULONG Unknown7;
ULONG Unknown8;
};

HANDLE NtCreateThreadEx(HANDLE process, LPTHREAD_START_ROUTINE Start, LPVOID lpParameter){

HMODULE modNtDll = LoadLibrary("ntdll.dll");

if(!modNtDll){
cout<<"Error loading ntdll.dll"<<endl;
return 0;
}

LPFUN_NtCreateThreadEx funNtCreateThreadEx = (LPFUN_NtCreateThreadEx) GetProcAddress(modNtDll, "NtCreateThreadEx");

if(!funNtCreateThreadEx){
cout<<"Error loading NtCreateThreadEx()"<<endl;
return 0;
}
NtCreateThreadExBuffer ntbuffer;

memset (&ntbuffer,0,sizeof(NtCreateThreadExBuffer));
DWORD temp1 = 0;
DWORD temp2 = 0;

ntbuffer.Size = sizeof(NtCreateThreadExBuffer);
ntbuffer.Unknown1 = 0x10003;
ntbuffer.Unknown2 = 0x8;
ntbuffer.Unknown3 = &temp2;
ntbuffer.Unknown4 = 0;
ntbuffer.Unknown5 = 0x10004;
ntbuffer.Unknown6 = 4;
ntbuffer.Unknown7 = &temp1;
// ntbuffer.Unknown8 = 0;

HANDLE hThread;
NTSTATUS status = funNtCreateThreadEx(
&hThread,
0x1FFFFF,
NULL,
process,
(LPTHREAD_START_ROUTINE) Start,
lpParameter,
FALSE, //start instantly
0, //null
0, //null
0, //null
&ntbuffer
);


return hThread;

}


//so to use in the above code like this:

HANDLE thread = NtCreateThreadEx(p, (LPTHREAD_START_ROUTINE)MyFuncAddress, DataAddress);
//
//

DLL INJECTION

Performing Dll injection is much more easier, we don't have to create a struct of parameters beacause LoadLibraryA has only 1 parameter


#include <windows.h>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include "ntdef.h"
#include <tlhelp32.h>

//For Vista/Win7:
HANDLE NtCreateThreadEx(HANDLE process, LPTHREAD_START_ROUTINE Start, LPVOID lpParameter);

using namespace std;

DWORD getPid(string procName);
int privileges();

int main()
{
privileges(); //don't mind of the result, because maybe it fails because you already have that privilege

DWORD pid = getPid("notepad.exe");
if (pid==0) return 1; //error

HANDLE p;
p = OpenProcess(PROCESS_ALL_ACCESS,false,pid);
if (p==NULL) return 1; //error

char * dll = "C:\\mydll.dll"

//--------now we are ready to inject

unsigned long LoadLib = (unsigned long)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");

LPVOID DataAddress = VirtualAllocEx(p, NULL, strlen(dll) + 1, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);

WriteProcessMemory(p, DataAddress, dll, strlen(dll), NULL);


HANDLE thread = CreateRemoteThread(p, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLib, DataAddress, 0, NULL);
//For Vista/Win7
//HANDLE thread = NtCreateThreadEx(p, (LPTHREAD_START_ROUTINE)LoadLib, DataAddress);

if (thread!=0){
//injection completed
WaitForSingleObject(thread, INFINITE); //this waits untill thread thread has finished
VirtualFree(MyFuncAddress, 0, MEM_RELEASE); //free myFunc memory
VirtualFree(DataAddress, 0, MEM_RELEASE); //free data memory
CloseHandle(thread);
CloseHandle(p); //don't wait for the thread to finish, just close the handle to the process
cout<<"Injection completed!"<<endl;
}else{
cout<<"Error!"<<endl;
}


system("PAUSE");
return EXIT_SUCCESS;
}

DWORD getPid(string procName){
HANDLE hsnap;
PROCESSENTRY32 pt;
hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
pt.dwSize = sizeof(PROCESSENTRY32);
do{
if(pt.szExeFile == procName){
DWORD pid = pt.th32ProcessID;
CloseHandle(hsnap);
return pid;
}
} while(Process32Next(hsnap, &pt));
CloseHandle(hsnap);
return 0;
}

int privileges(){
HANDLE Token;
TOKEN_PRIVILEGES tp;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&Token))
{
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(Token, 0, &tp, sizeof(tp), NULL, NULL)==0){
return 1; //FAIL
}else{
return 0; //SUCCESS
}
}
return 1;
}





//for VISTA/WIN7



typedef NTSTATUS (WINAPI *LPFUN_NtCreateThreadEx)
(
OUT PHANDLE hThread,
IN ACCESS_MASK DesiredAccess,
IN LPVOID ObjectAttributes,
IN HANDLE ProcessHandle,
IN LPTHREAD_START_ROUTINE lpStartAddress,
IN LPVOID lpParameter,
IN BOOL CreateSuspended,
IN DWORD StackZeroBits,
IN DWORD SizeOfStackCommit,
IN DWORD SizeOfStackReserve,
OUT LPVOID lpBytesBuffer
);

struct NtCreateThreadExBuffer
{
ULONG Size;
ULONG Unknown1;
ULONG Unknown2;
PULONG Unknown3;
ULONG Unknown4;
ULONG Unknown5;
ULONG Unknown6;
PULONG Unknown7;
ULONG Unknown8;
};

HANDLE NtCreateThreadEx(HANDLE process, LPTHREAD_START_ROUTINE Start, LPVOID lpParameter){

HMODULE modNtDll = LoadLibrary("ntdll.dll");

if(!modNtDll){
cout<<"Error loading ntdll.dll"<<endl;
return 0;
}

LPFUN_NtCreateThreadEx funNtCreateThreadEx = (LPFUN_NtCreateThreadEx) GetProcAddress(modNtDll, "NtCreateThreadEx");

if(!funNtCreateThreadEx){
cout<<"Error loading NtCreateThreadEx()"<<endl;
return 0;
}
NtCreateThreadExBuffer ntbuffer;

memset (&ntbuffer,0,sizeof(NtCreateThreadExBuffer));
DWORD temp1 = 0;
DWORD temp2 = 0;

ntbuffer.Size = sizeof(NtCreateThreadExBuffer);
ntbuffer.Unknown1 = 0x10003;
ntbuffer.Unknown2 = 0x8;
ntbuffer.Unknown3 = &temp2;
ntbuffer.Unknown4 = 0;
ntbuffer.Unknown5 = 0x10004;
ntbuffer.Unknown6 = 4;
ntbuffer.Unknown7 = &temp1;
// ntbuffer.Unknown8 = 0;

HANDLE hThread;
NTSTATUS status = funNtCreateThreadEx(
&hThread,
0x1FFFFF,
NULL,
process,
(LPTHREAD_START_ROUTINE) Start,
lpParameter,
FALSE, //start instantly
0, //null
0, //null
0, //null
&ntbuffer
);


return hThread;

}

so if we want to check which OS are we running so to use CreateRemoteThread and NtCreateThreadEx:


int CheckOSVersion()
{
/*
* Windows XP = 1 (NT 5.0)
* Windows Vista = 2 (NT 6.0)
* Windows 7 = 3 (NT 6.1)
* Windows 8 = 4 (NT 6.2) --> on Windows 8 CreateRemoteThread works perfectly!!
*/
OSVERSIONINFO osver;
osver.dwOSVersionInfoSize = sizeof(osver);
if (GetVersionEx(&osver))
{
if (!(osver.dwPlatformId == VER_PLATFORM_WIN32_NT))
return 0;
if (osver.dwMajorVersion == 5)
return 1;
if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0)
return 2;
if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1)
return 3;
if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2)
return 4;
}
else
return 0;
}

//use:

char type[50];

int os = CheckOSVersion();
if (os == 0) return 0;
if (os==1) strcpy(type, "Windows XP");
if (os==2) strcpy(type, "Windows Vista");
if (os==3) strcpy(type, "Windows 7");
if (os==4) strcpy(type, "Windows 8");

if you want to check if you are on a 64bit or 32bit OS by code:

//the size of void* is the answer
if (sizeof(void*) == 4) //is 32bit
if (sizeof(void*) == 8) //is 64bit

Other way

I found many people talking about RtlCreateUserThread(), well it can be implemented easily (it is in ntdll.dll), but has a flaw, if you inject a dll with this function you cannot use CreateThread() inside it but you need to implement RtlCreateUserThread() in the dll too; i don't know why but it is.

The implementation is:


typedef struct ID{
PVOID UniqueProcess;
PVOID UniqueThread;
} CLIENT_ID, *PCLIENT_ID;

typedef long (*myRtlCreateUserThread) (HANDLE,
PSECURITY_DESCRIPTOR,
BOOLEAN,
ULONG,
PULONG,
PULONG,
PVOID,
PVOID,
PHANDLE,
PCLIENT_ID);

myRtlCreateUserThread RtlCreateUserThread;

RtlCreateUserThread=(myRtlCreateUserThread)GetProcAddress(GetModuleHandle("ntdll.dll"),"RtlCreateUserThread");

IMPORTANT: 32-BIT / 64-BIT

This is a portability-injection table:

- 32bit program inject 32bit dll in a 32bit target

- 32bit program inject 64bit dll in a 64bit target

- 64bit program inject 32bit dll in a 32bit target

- 64bit program inject 64bit dll in a 64bit target

the first type and the fourth type are easy to code, but if you dare getting in troubles with the second and the third take a look at this paper:

http://www.corsix.or...ction-and-wow64

2) Code injection with SetWindowsHookEx

Setting hooks is a tipical action of keyloggers over WH_KEYBOARD hook type.

This method makes them perfect in capturing key strokes BUT if we inject a dll using hooks the program that set the hook must keep running otherwise the dll is suddenly unloaded.

To perform this type of injection we don't need directly the PID of the process but the Thread ID of it.

We obtain the Thread ID from the PID:


DWORD GetThreadID(DWORD pid){
HANDLE hsnap;
THREADENTRY32 pt;
hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
pt.dwSize = sizeof(THREADENTRY32);
while (Thread32Next(hsnap, &pt)){
if(pt.th32OwnerProcessID == pid){
DWORD Thpid = pt.th32ThreadID;
CloseHandle(hsnap);
return Thpid;
}
};
CloseHandle(hsnap);
return 0;
}


Now let's jot down some code about SetWindowsHookEx()


#include <cstdlib>
#include <iostream>
#include "windows.h"
#include "tlhelp32.h"

using namespace std;

DWORD getPid(string procName);
DWORD GetThreadID(DWORD pid);


int main(int argc, char *argv[])
{
HHOOK hproc;
HOOKPROC cbt;
HMODULE dll = LoadLibrary("DllHook.dll"); //the dll tha we will inject that contains the hook procedure
cbt = (HOOKPROC)GetProcAddress(dll, "MyProcedure"); //get the address of our Procedure
DWORD id = GetThreadID(getPid("notepad.exe")); //in this example we want to set the hook in a specific target

if (id == 0) return 0; //if id == 0 means that the process isn't running
hproc = SetWindowsHookEx(WH_KEYBOARD, cbt, dll, id); //if we wanted to set the hook in every process we could replace 'id' with 0

cin.get();
UnhookWindowsHookEx(hproc); //When we want to remove the hook
return EXIT_SUCCESS;
}

DWORD GetThreadID(DWORD pid){
HANDLE hsnap;
THREADENTRY32 pt;
hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
pt.dwSize = sizeof(THREADENTRY32);
while (Thread32Next(hsnap, &pt)){
if(pt.th32OwnerProcessID == pid){
DWORD Thpid = pt.th32ThreadID;
CloseHandle(hsnap);
return Thpid;
}
};
CloseHandle(hsnap);
return 0;
}

DWORD getPid(string procName){
HANDLE hsnap;
PROCESSENTRY32 pt;
hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
pt.dwSize = sizeof(PROCESSENTRY32);
do{
if(!strcmp(pt.szExeFile, procName.c_str())){
DWORD pid = pt.th32ProcessID;
CloseHandle(hsnap);
return pid;
}
} while(Process32Next(hsnap, &pt));
CloseHandle(hsnap);
return 0;
}

Now the our Dll that contains the hook procedure (in this case is named DllHook.dll)


#include <windows.h>
#include <stdio.h>
#include <stdlib.h>


__declspec(dllexport) LRESULT WINAPI MyProcedure(int code, WPARAM wp, LPARAM lp);

__declspec(dllexport) LRESULT WINAPI MyProcedure(int code, WPARAM wp, LPARAM lp){

//here goes our code

return CallNextHookEx(NULL, code, wp, lp); //this is needed to let other applications set other hooks on this target
}


BOOL APIENTRY DllMain (HINSTANCE hInst,
DWORD reason,
LPVOID reserved)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:

break;

case DLL_PROCESS_DETACH:
break;

case DLL_THREAD_ATTACH:
break;

case DLL_THREAD_DETACH:
break;
}

/* Returns TRUE on success, FALSE on failure */
return TRUE;
}


3) Code Injection modifying the Main Thread

This part is a bit more complicated, but works on any version of WINDOWS and doesn't need to keep the injector running

steps:

- Open the target Process through the PID (Api used: OpenProcess())

- Allocate space in the remote process for our function and parameters (Api used: VirtualAllocEx())

- Get the target process's thread ID

- Open the remote thread and suspend it (Api used: OpenThread() and SupendThread())

- Get the remote thread context (Api used: GetThreadContext())

- Saving the current Eip and setting it to the address of our injected function

- Write our function and parameters in the remote process (Api used: WriteProcessMemory())

- PATCH IN RUNTIME the injected function with the addresses of our parameters (Api used: WriteProcessMemory())

- Set the new remote thread context (Api used: SetThreadContext())

- Resume the remote thread and optionally free the memory (Api used: ResumeThread())

Before seeing the code i want to explain what our function will be.

It is an assembly code (or shellcode) that performs our operation, but while coding we can't know the addresses of our parameters so we put placeholders, in other words, we put a label that will be replaced during execution with the right addresses.

the assembly function is:


push 0xACEACEAC ;-> placeholder for the address of our old EIP
pushfd ;->save all flags registers
pushad ;-> save all registers

push 0xACEACEAC ;->placeholder for the address of the string 'User32.dll'
mov ecx, 0xACEACEAC ;->placeholder for the address of LoadLibraryA
call ecx ;-> traslated in c++: LoadLibrary("User32.dll")

;now the address of the LOADED LIBRARY User32.dll is in eax register

push 0xACEACEAC ;->placeholder for the address of the string MessageBoxA
push eax ;->push User32.dll into the stack
mov edx,0xACEACEAC ;->placeholder for the address of GetProcAddress
call edx ;translated in c++: GetProcAddress(LoadLibrary("User32.dll"), "MessageBoxA")

;now the address of MessageBoxA is in eax register

push 0 ;push the fourth parameter of MessageBoxA (MB_OK)
push 0xACEACEAC ;->placeholder for the address of the text (3 parameter)
push 0xACEACEAC ;->placeholder for the address of the caption (2 parameter)
push 0 ;push the first parameter into the stack (don't bother)
call eax ;translated in c++: MessageBox(0, "caption", "text", MB_OK)

popad ;restore all the registers
popfd ;restore all the flags
ret ;get back to right execution

as i said before we can inject an assembly code or shellcode (they behave in the same way), so that assembly code converted in shellcode is:


char shellcode[] = "\x68\xac\xce\xea\xac\x9c\x60\x68\xac\xce\xea\xac\xb9\xac\xce\xea\xac\xff\xd1\x68\xac\xce\xea\xac\x50\xba\xac\xce\xea\xac\xff\xd2\x6a\x00\x68\xac\xce\xea\xac\x68\xac\xce\xea\xac\x6a\x00\xff\xd0\x61\x9d\xc3";

now lets see the real full code:

#include <windows.h>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <tlhelp32.h>
#include <shlwapi.h>

#pragma comment(lib, "shlwapi.lib")

using namespace std;

int privileges();
DWORD getPid(string procName);
DWORD GetThreadID(DWORD pid);
__declspec() void myFunc();
__declspec() void Useless();

int _tmain()
{
privileges();
unsigned long oldIP;


DWORD pid = getPid("notepad.exe");
if (pid==0) return 1;
cout<<pid<<endl;

HANDLE p;
p = OpenProcess(PROCESS_ALL_ACCESS,false,pid);
if (p==NULL) return 1; //error

char * user32 = "User32.dll";
char * MsgBox = "MessageBoxA";
char * testo = "REPORT";
char * mex = "INJECTION THREAD: SUCCESS!";

unsigned long size_myFunc = (unsigned long)Useless - (unsigned long)myFunc;
unsigned long GetProcAdr = (unsigned long)GetProcAddress(GetModuleHandle("kernel32.dll"), "GetProcAddress");
unsigned long Load32 = (unsigned long)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");

void * mexAddress = VirtualAllocEx(p, NULL, strlen(mex)+1, MEM_COMMIT, PAGE_READWRITE);
void * testoAddress = VirtualAllocEx(p, NULL, strlen(testo)+1, MEM_COMMIT, PAGE_READWRITE);
void * MsgboxAddress = VirtualAllocEx(p, NULL, strlen(MsgBox)+1, MEM_COMMIT, PAGE_READWRITE);
void * DataAddress = VirtualAllocEx(p, NULL, strlen(user32)+1, MEM_COMMIT, PAGE_READWRITE);
void * MyFuncAddress = VirtualAllocEx(p, NULL, size_myFunc, MEM_COMMIT, PAGE_EXECUTE_READWRITE);


WriteProcessMemory(p, DataAddress, user32, strlen(user32), NULL); //string user32.dll
WriteProcessMemory(p, MsgboxAddress, MsgBox, strlen(MsgBox), NULL); //string MessageBoxA
WriteProcessMemory(p, testoAddress, testo, strlen(testo), NULL); //string for caption
WriteProcessMemory(p, mexAddress, mex, strlen(mex), NULL); //string for text

DWORD thID = GetThreadID(pid);
HANDLE hThread = OpenThread((THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME), false, thID);

SuspendThread(hThread);


CONTEXT ctx;
ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(hThread, &ctx);
oldIP = ctx.Eip;

ctx.Eip = (DWORD)MyFuncAddress;
ctx.ContextFlags = CONTEXT_CONTROL;


WriteProcessMemory(p, MyFuncAddress, myFunc,size_myFunc, NULL);
//After writing the function we patch it with the right addresses
WriteProcessMemory(p, (void*)((unsigned long)MyFuncAddress + 1), &oldIP, 4, NULL);
WriteProcessMemory(p, (void*)((unsigned long)MyFuncAddress + 8), &DataAddress, 4, NULL);
WriteProcessMemory(p, (void*)((unsigned long)MyFuncAddress + 13), &Load32, 4, NULL); //CARICATO USER32.DLL
WriteProcessMemory(p, (void*)((unsigned long)MyFuncAddress + 20), &MsgboxAddress, 4, NULL);
WriteProcessMemory(p, (void*)((unsigned long)MyFuncAddress + 26), &GetProcAdr, 4, NULL);
WriteProcessMemory(p, (void*)((unsigned long)MyFuncAddress + 35), &testoAddress, 4, NULL);
WriteProcessMemory(p, (void*)((unsigned long)MyFuncAddress + 40), &mexAddress, 4, NULL);

SetThreadContext(hThread, &ctx);
ResumeThread(hThread);

Sleep(1000); //wait a second!

//if we want to free the used memory and the injected code that will take a short time of execution,
//we can of course wait for it for a certain period with Sleep();
//but if the code will keep running with no ending we cannot free the memory otherwise it will crash the target application
//VirtualFreeEx(p, MyFuncAddress, size_myFunc, MEM_DECOMMIT);
//VirtualFreeEx(p, DataAddress, strlen(mytext)+1, MEM_DECOMMIT);
CloseHandle(p);
CloseHandle(hThread);

system("PAUSE");
return EXIT_SUCCESS;
}







DWORD GetThreadID(DWORD pid){
HANDLE hsnap;
THREADENTRY32 pt;
hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
pt.dwSize = sizeof(THREADENTRY32);
while (Thread32Next(hsnap, &pt)){
if(pt.th32OwnerProcessID == pid){
DWORD Thpid = pt.th32ThreadID;
CloseHandle(hsnap);
return Thpid;
}
};
CloseHandle(hsnap);
return 0;
}

DWORD getPid(string procName){
HANDLE hsnap;
PROCESSENTRY32 pt;
hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
pt.dwSize = sizeof(PROCESSENTRY32);
do{
if(!strcmp(pt.szExeFile, procName.c_str())){
DWORD pid = pt.th32ProcessID;
CloseHandle(hsnap);
return pid;
}
} while(Process32Next(hsnap, &pt));
CloseHandle(hsnap);
return 0;
}




__declspec(naked) void myFunc(){
_asm {
push 0xACEACEAC
pushfd
pushad

push 0xACEACEAC
mov ecx, 0xACEACEAC
call ecx

push 0xACEACEAC
push eax
mov edx,0xACEACEAC
call edx

push 0
push 0xACEACEAC
push 0xACEACEAC
push 0
call eax

popad
popfd
ret
}

}


__declspec(naked) void Useless(){ //this let's us calculate the address of MyFunc
_asm ret;
}



int privileges(){
HANDLE Token;
TOKEN_PRIVILEGES tp;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&Token))
{
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(Token, 0, &tp, sizeof(tp), NULL, NULL)==0){
return 1; //FAIL
}else{
return 0; //SUCCESS
}
}
return 1;
}

Now i want to explain a bit for who didn't understand how to patch the function.

Before i stated that i put placeholders that will be replaced with the right addresses, to help you i posted the shellcode that come handy when looking for the offset(position) of the placeholders.

take a look at it, we want to patch the first item (oldIP), the placeholder is 0xACEACEAC that translated in hex is "\xac\xce\xea\xac".

Now, you need to know that "\xXX" you see is a traslated value, and the first time we meet "\xac\xce\xea\xac" is after 1 "\xXX"...

we can consider any "\xXX" such as a posistion, so:

. 0 . 1 . 2 . 3 . 4 . 5 . 6 .   ...
"\x68\xac\xce\xea\xac\x9c\x60 ...

so, the beginning address of MyFuncAddress corrisponds to . 0 . ( = \x68 ), and the beginning of the placeholder to . 1 ., so MyFuncAddress + 1... here we write the right address that will replace the first "\xac\xce\xea\xac"

if we look for the second we find it in the eighth position so MyFuncAddress + 8... so on until we patch them all.

we convent MyFuncAddress from void* to unsigned long so to do an aritmethic sum, then we convert the result back to void*

(void*)((unsigned long) MyFuncAddress + each_offset)

I noticed that people that use Dev-C++ get an error because it doesn't find OpenThread() and an error with asm tags, well i suggest you to get VisualC++...

btw now i show you in a DLL INJECTION how you can get dinamically OpenThread() from kernel32.dll and use the shellcode instead of an asm tags:


#include <windows.h>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <tlhelp32.h>
#include <shlwapi.h>

#pragma comment(lib, "shlwapi.lib")
using namespace std;

char shellcode[] = "\x68\xac\xce\xea\xac\x9c\x60\x68\xac\xce\xea\xac\xb8\xac\xce\xea\xac\xff\xd0\x61\x9d\xc3";

typedef HANDLE (WINAPI* OpenThreadfunc)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId);
OpenThreadfunc myOpenThread;

void setOpenThread();
int privileges();
DWORD getPid(string procName);
DWORD GetThreadID(DWORD pid);
int injectLibrary(char * process, char * dll);

HMODULE kernel;

int main(int argc, char *argv[])
{

injectLibrary("notepad.exe", "C:\\fullpath\\myDll");

system("PAUSE");
return EXIT_SUCCESS;
}

int injectLibrary(char * process, char * dll){

setOpenThread();
if (myOpenThread == NULL){
cout<<"Error with OpenThread()"<<endl;
return 1;
}

unsigned long oldIP;

if (privileges()==1){ //we if you want to check privileges you can, but some times if you are administrator you can perform injection without them
cout<<"Error couldn't get privileges..."<<endl;
}

DWORD pid = getPid("notepad.exe");
if (pid==0) return 1;


HANDLE p;
p = OpenProcess(PROCESS_ALL_ACCESS,false,pid);
if (p==NULL) return 1; //error


char * dllName = dll;

unsigned long shsize = sizeof(shellcode);
unsigned long Load32 = (unsigned long)GetProcAddress(kernel, "LoadLibraryA");

void * DllAddress = VirtualAllocEx(p, NULL, strlen(dllName)+ 1, MEM_COMMIT,PAGE_READWRITE);
void * MyFuncAddress = VirtualAllocEx(p, NULL, shsize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

WriteProcessMemory(p, DllAddress, dllName, strlen(dllName), NULL);

DWORD thID = GetThreadID(pid);
HANDLE hThread = myOpenThread((THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME), false, thID);

SuspendThread(hThread);
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(hThread, &ctx);
oldIP = ctx.Eip;
ctx.Eip = (DWORD)MyFuncAddress;
ctx.ContextFlags = CONTEXT_CONTROL;

WriteProcessMemory(p, MyFuncAddress, &shellcode, shsize, NULL);
WriteProcessMemory(p, (void*)((unsigned long)MyFuncAddress + 1), &oldIP, 4, NULL);
WriteProcessMemory(p, (void*)((unsigned long)MyFuncAddress + 8), &DllAddress, 4, NULL);
WriteProcessMemory(p, (void*)((unsigned long)MyFuncAddress + 13), &Load32, 4, NULL);

SetThreadContext(hThread, &ctx);
ResumeThread(hThread);

CloseHandle(p);
CloseHandle(hThread);
FreeLibrary(kernel);
return 0;
}


void setOpenThread(){
kernel = LoadLibrary("kernel32.dll");
if (kernel != NULL) myOpenThread = (OpenThreadfunc)GetProcAddress(kernel, "OpenThread");
}


DWORD getPid(string procName){
HANDLE hsnap;
PROCESSENTRY32 pt;
hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
pt.dwSize = sizeof(PROCESSENTRY32);
do{
if(!strcmp(pt.szExeFile, procName.c_str())){
DWORD pid = pt.th32ProcessID;
CloseHandle(hsnap);
return pid;
}
} while(Process32Next(hsnap, &pt));
CloseHandle(hsnap);
return 0;
}





DWORD GetThreadID(DWORD pid){
HANDLE hsnap;
THREADENTRY32 pt;
hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
pt.dwSize = sizeof(THREADENTRY32);
while (Thread32Next(hsnap, &pt)){
if(pt.th32OwnerProcessID == pid){
DWORD Thpid = pt.th32ThreadID;
CloseHandle(hsnap);
return Thpid;
}
};
CloseHandle(hsnap);
return 0;
}

int privileges(){
HANDLE Token;
TOKEN_PRIVILEGES tp;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&Token))
{
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(Token, 0, &tp, sizeof(tp), NULL, NULL)==0){
return 1; //FAIL
}else{
return 0; //SUCCESS
}
}
return 1;
}


WELL, FINISH!! I hope this tutorial will help you!

ENJOY CODING!

RosDevil

Sursa: Code Injections [beginner and advanced] - rohitab.com - Forums

Posted

Destul de interesant, bookmarked pe mai tarziu.

Totusi am o intrebare, in coduri de ce e folosit memset in loc de ZeroMemory ?

Nu sunt foarte avansat in injectii si ma intrebam care e avantajul folosirii unuia fata de celalalt?

Posted
Destul de interesant, bookmarked pe mai tarziu.

Totusi am o intrebare, in coduri de ce e folosit memset in loc de ZeroMemory ?

Nu sunt foarte avansat in injectii si ma intrebam care e avantajul folosirii unuia fata de celalalt?

Stiam ca e un macro, dar nu stiam cum e definit si dupa mici cautari:

WinBase.h

#define ZeroMemory RtlZeroMemory

RtlZeroMemory e definit in WDH.h:

#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))

Aparent e acelasi lucru. E probabil insa sa fie mici diferente la apel, "memset" probabil va apela wrapper-ul din runtime-ul de la Visual C iar apelul ZeroMemory e posibil sa fie executat direct in kernel (RtlZeroMemory routine (Windows Drivers)).

O sa fac putin research sa vad.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...