Click here to Skip to main content
15,886,199 members
Articles / Programming Languages / C
Tip/Trick

Code Injection - A Generic Approach for 32bit and 64bit Versions

Rate me:
Please Sign up or sign in to vote.
4.73/5 (8 votes)
7 Mar 2014CPOL 27.4K   19   8
Code Injection - A Generic Approach for 32bit and 64bit Versions

Introduction

In my previous article, I released code for injecting into running explorer.exe on 32 bit platform which uses 32 bit instructions as shell code which were injected in the process.

Here, we will see a generic code which does not involve any shell code or assembly instructions that are hard coded in the injector, whereas it transfers this responsibility to compiler to prepare the proper assembly for 32 bit and 64 bit version.

Refer to my previous tip Code Injection.

Code

C++
/*
    Application:    Code injection into a running process.
    Author:            _RT
    Dated:            07-March-2014
*/

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

#pragma comment(lib,"advapi32.lib")
#pragma comment(lib,"user32.lib")

typedef BOOL (WINAPI* CreatePrcssParam)(LPCTSTR, LPTSTR, LPSECURITY_ATTRIBUTES, 
    LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCTSTR, LPVOID, LPVOID);

struct PARAMETERS{
    LPVOID CreateProcessInj;
    char lpApplicationName[50];
    char lpCommandLine[10];
    LPSECURITY_ATTRIBUTES lpProcessAttributes;
    LPSECURITY_ATTRIBUTES lpThreadAttributes;
    BOOL bInheritHandles;
    DWORD dwCreationFlags;
    LPVOID lpEnvironment;
    LPCTSTR lpCurrentDirectory;
    LPVOID lpStartupInfo;
    LPVOID lpProcessInformation;
};

int privileges();
DWORD myFunc(PARAMETERS * myparam);
DWORD Useless();    //used to calculate size of myFunc()

int main()
{
    privileges();

    _STARTUPINFOA si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    DWORD pid;
    GetWindowThreadProcessId(FindWindow(NULL, L"Start Menu"), &pid);

    HANDLE p;
    p = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
    if (p == NULL)
    {
        printf("ERROR");
        return 1; //error
    }

    char * AppName = "C:\\Windows\\notepad.exe";
    char * CmdLine = "";

  //Writing the structure vital for CreateProcess function
    LPVOID StrtUpInfo = VirtualAllocEx(p, NULL, sizeof(si), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(p, StrtUpInfo, &si, sizeof(si), NULL);

    LPVOID PrcssInfo = VirtualAllocEx(p, NULL, sizeof(si), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(p, PrcssInfo, &pi, sizeof(pi), NULL);
  //=========================================================

    PARAMETERS data = {0};
    HMODULE Kernel32 = LoadLibrary(L"Kernel32.dll");
    data.CreateProcessInj = GetProcAddress(Kernel32, "CreateProcessA");
    strcpy_s(data.lpApplicationName,AppName);
    strcpy_s(data.lpCommandLine, CmdLine);
    data.lpProcessAttributes = NULL;
    data.lpThreadAttributes = NULL;
    data.bInheritHandles = FALSE;
    data.dwCreationFlags = NULL;
    data.lpEnvironment = NULL;
    data.lpCurrentDirectory = NULL;
    data.lpStartupInfo = StrtUpInfo;
    data.lpProcessInformation = PrcssInfo;

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

    //Writing the code part of myFunc -- Instructions to be executed
    LPVOID MyFuncAddress = VirtualAllocEx(p, NULL, size_myFunc, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    WriteProcessMemory(p, MyFuncAddress, (void*)myFunc, size_myFunc, NULL);

    //Writing the data part of myFunc -- Parameters of the functios
    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 for it to end and free the memory
        WaitForSingleObject(thread, INFINITE);   //this waits until 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
    }
    else{
        printf("Error!");
    }
    return EXIT_SUCCESS;
}

static DWORD myFunc(PARAMETERS * myparam){
    
    CreatePrcssParam CreatePrcss = (CreatePrcssParam)myparam->CreateProcessInj;
    BOOL result = CreatePrcss((LPCTSTR)myparam->lpApplicationName, NULL, 
    myparam->lpProcessAttributes, myparam->lpThreadAttributes, 
    myparam->bInheritHandles, myparam->dwCreationFlags, myparam->lpEnvironment, 
    myparam->lpCurrentDirectory, myparam->lpStartupInfo, myparam->lpProcessInformation);
    return 0;
}

static 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;
}

What you have to do is just compile this code in 32 bit mode if you want a 32 bit injector or in 64 bit mode if you need a 64 bit injector.

This code forces the arguments of CreateProcess function to be stack based and these parameters are passed using the lpParameter field of CreateRemoteThread function so there will be no unresolved addresses of parameters when the injection part is ported to a foreign process.

Other information on how to prevent code injection is explained in my previous tip.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionbest idea Pin
ShenXiaoLong7-Jan-18 23:40
ShenXiaoLong7-Jan-18 23:40 
great! calculate function size and copy function code to target process, then execute it.
AnswerRe: best idea Pin
ShenXiaoLong10-Jan-18 20:59
ShenXiaoLong10-Jan-18 20:59 
Questionproblem for me on x64 platform Pin
rtischer827717-Apr-17 5:47
rtischer827717-Apr-17 5:47 
AnswerRe: problem for me on x64 platform Pin
rtischer827718-Apr-17 8:00
rtischer827718-Apr-17 8:00 
QuestionCommanLine issue Pin
zbychus1-May-15 1:26
zbychus1-May-15 1:26 
AnswerRe: CommanLine issue Pin
zbychus1-May-15 1:48
zbychus1-May-15 1:48 
Questioncode injection triggered by explorer Pin
jk-newbie12-May-14 14:18
jk-newbie12-May-14 14:18 
AnswerRe: code injection triggered by explorer Pin
_Ravikant Tiwari_19-May-14 18:57
professional_Ravikant Tiwari_19-May-14 18:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.