Initial commit
This commit is contained in:
commit
99f0599bb1
9 changed files with 1219 additions and 0 deletions
492
ps.c
Normal file
492
ps.c
Normal file
|
|
@ -0,0 +1,492 @@
|
|||
#include "ps.h"
|
||||
#include <Psapi.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static process_t _ps_this_process;
|
||||
|
||||
process_t* ps_this_process = &_ps_this_process;
|
||||
pe_t* ps_this_module = NULL;
|
||||
|
||||
DWORD ps_page_size;
|
||||
DWORD ps_page_mask;
|
||||
DWORD ps_page_power;
|
||||
|
||||
static HMODULE _hMods[1024];
|
||||
|
||||
static LPCSTR s_szGlobalModules[] = {
|
||||
"ntdll",
|
||||
"kernel32"
|
||||
};
|
||||
|
||||
static BOOL _ps_is_global_module(LPCSTR lpModuleName)
|
||||
{
|
||||
CHAR szModuleName[64];
|
||||
strcpy_s(szModuleName, sizeof(szModuleName), lpModuleName);
|
||||
_strlwr_s(szModuleName, sizeof(szModuleName));
|
||||
|
||||
SIZE_T uNameLen = strlen(lpModuleName);
|
||||
for (DWORD i = 0; i < sizeof(s_szGlobalModules) / sizeof(LPCSTR); i++)
|
||||
{
|
||||
LPCSTR lpCurrentModule = s_szGlobalModules[i];
|
||||
SIZE_T uCurrentNameLen = strlen(lpCurrentModule);
|
||||
if (!memcmp(lpCurrentModule, szModuleName,
|
||||
min(min(uNameLen,uCurrentNameLen), sizeof(szModuleName))))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static DWORD _log2(DWORD dwNum)
|
||||
{
|
||||
DWORD dwPower = 0;
|
||||
while (dwNum >>= 1) dwPower++;
|
||||
return dwPower;
|
||||
}
|
||||
|
||||
void ps_init()
|
||||
{
|
||||
DWORD cbNeeded = 0;
|
||||
SYSTEM_INFO sysInfo;
|
||||
|
||||
GetSystemInfo(&sysInfo);
|
||||
ps_page_size = sysInfo.dwPageSize;
|
||||
ps_page_mask = ps_page_size - 1;
|
||||
ps_page_power = _log2(ps_page_size);
|
||||
|
||||
ps_this_process->hProcess = GetCurrentProcess();
|
||||
|
||||
EnumProcessModules(ps_this_process->hProcess, _hMods, sizeof(_hMods), &cbNeeded);
|
||||
ps_this_process->dwModules = cbNeeded / sizeof(HMODULE);
|
||||
ps_this_process->pModules = (pe_t*)calloc(ps_this_process->dwModules, sizeof(pe_t));
|
||||
|
||||
CHAR szExePath[MAX_PATH];
|
||||
|
||||
GetProcessImageFileName(ps_this_process->hProcess, szExePath, MAX_PATH);
|
||||
PSTR pExeName = strrchr(szExePath, '\\') + 1;
|
||||
|
||||
CHAR szModulePath[MAX_PATH];
|
||||
for (DWORD i = 0; i < ps_this_process->dwModules; i++)
|
||||
{
|
||||
pe_t* mod = &ps_this_process->pModules[i];
|
||||
|
||||
mod->BaseAddress = (ULONG_PTR)_hMods[i];
|
||||
mod->pDos = (PIMAGE_DOS_HEADER)mod->BaseAddress;
|
||||
mod->pNt = (PIMAGE_NT_HEADERS)((PCHAR)mod->pDos + mod->pDos->e_lfanew);
|
||||
|
||||
GetModuleFileName(_hMods[i], szModulePath, MAX_PATH);
|
||||
PSTR pModuleName = strrchr(szModulePath, '\\') + 1;
|
||||
strcpy_s(mod->szName, sizeof(mod->szName), pModuleName);
|
||||
if (!strcmp(pModuleName, pExeName))
|
||||
ps_this_process->pExe = mod;
|
||||
}
|
||||
|
||||
//Find current module
|
||||
ULONG_PTR ThisFunction = (ULONG_PTR)&ps_init;
|
||||
for (DWORD i = 0; i < ps_this_process->dwModules; i++)
|
||||
{
|
||||
pe_t* mod = &ps_this_process->pModules[i];
|
||||
ULONG_PTR CodeStart = mod->BaseAddress
|
||||
+ mod->pNt->OptionalHeader.BaseOfCode;
|
||||
ULONG_PTR CodeEnd = CodeStart
|
||||
+ mod->pNt->OptionalHeader.SizeOfCode;
|
||||
if (ThisFunction >= CodeStart && ThisFunction < CodeEnd)
|
||||
{
|
||||
ps_this_module = mod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ps_this_module)
|
||||
{
|
||||
//Module not found.
|
||||
//Maybe we're not a DLL but a custom code loader/injector?
|
||||
//Anyway, redirect to EXE module.
|
||||
ps_this_module = ps_this_process->pExe;
|
||||
}
|
||||
}
|
||||
|
||||
void ps_exit()
|
||||
{
|
||||
free(ps_this_process->pModules);
|
||||
}
|
||||
|
||||
DWORD ps_round_to_page(DWORD dwSize)
|
||||
{
|
||||
return ((dwSize >> ps_page_power) + (dwSize & ps_page_mask ? 1 : 0)) << ps_page_power;
|
||||
}
|
||||
|
||||
process_t* ps_load_process(DWORD dwPid)
|
||||
{
|
||||
HANDLE hProcess;
|
||||
DWORD cbNeeded = 0;
|
||||
|
||||
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
|
||||
if (hProcess == INVALID_HANDLE_VALUE) return NULL;
|
||||
process_t* ps = (process_t*)malloc(sizeof(process_t));
|
||||
ps->hProcess = hProcess;
|
||||
|
||||
EnumProcessModules(ps->hProcess, _hMods, sizeof(_hMods), &cbNeeded);
|
||||
DWORD dwModules = cbNeeded / sizeof(HMODULE);
|
||||
ps->pModules = (pe_t*)calloc(dwModules, sizeof(pe_t));
|
||||
CHAR szExePath[MAX_PATH];
|
||||
|
||||
GetProcessImageFileName(ps->hProcess, szExePath, MAX_PATH);
|
||||
PSTR pExeName = strrchr(szExePath, '\\') + 1;
|
||||
|
||||
CHAR szModulePath[MAX_PATH];
|
||||
|
||||
IMAGE_DOS_HEADER dosHeader;
|
||||
IMAGE_NT_HEADERS ntHeaders;
|
||||
|
||||
ps->dwModules = 0;
|
||||
for (DWORD i = 0; i < dwModules; i++)
|
||||
{
|
||||
pe_t* mod = &ps->pModules[ps->dwModules];
|
||||
|
||||
mod->BaseAddress = (ULONG_PTR)_hMods[i];
|
||||
ps_read(ps, mod->BaseAddress, &dosHeader, sizeof(dosHeader));
|
||||
if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) continue;
|
||||
ps_read(ps, mod->BaseAddress + dosHeader.e_lfanew, &ntHeaders, sizeof(ntHeaders));
|
||||
if (ntHeaders.Signature != IMAGE_NT_SIGNATURE) continue;
|
||||
|
||||
SIZE_T uHdrSize = ntHeaders.OptionalHeader.SizeOfHeaders;
|
||||
PVOID pHeader = malloc(uHdrSize);
|
||||
ps_read(ps, mod->BaseAddress, pHeader, uHdrSize);
|
||||
|
||||
mod->pDos = (PIMAGE_DOS_HEADER)pHeader;
|
||||
mod->pNt = (PIMAGE_NT_HEADERS)((PCHAR)mod->pDos + mod->pDos->e_lfanew);
|
||||
|
||||
GetModuleFileNameEx(ps->hProcess, _hMods[i], szModulePath, MAX_PATH);
|
||||
PSTR pModuleName = strrchr(szModulePath, '\\') + 1;
|
||||
strcpy_s(mod->szName, sizeof(mod->szName), pModuleName);
|
||||
if (!strcmp(pModuleName, pExeName))
|
||||
ps->pExe = mod;
|
||||
|
||||
ps->dwModules++;
|
||||
}
|
||||
|
||||
return ps;
|
||||
}
|
||||
|
||||
void ps_unload_process(process_t* ps)
|
||||
{
|
||||
if (ps == ps_this_process) return;
|
||||
|
||||
for (DWORD i = 0; i < ps->dwModules; i++)
|
||||
free(ps->pModules[i].pDos);
|
||||
free(ps->pModules);
|
||||
CloseHandle(ps->hProcess);
|
||||
free(ps);
|
||||
}
|
||||
|
||||
SIZE_T ps_read(process_t* ps, ULONG_PTR Addr, LPVOID lpDst, SIZE_T Size)
|
||||
{
|
||||
SIZE_T Read = 0;
|
||||
if (ps == ps_this_process)
|
||||
{
|
||||
Read = Size;
|
||||
CopyMemory(lpDst, (LPCVOID)Addr, Size);
|
||||
}
|
||||
else ReadProcessMemory(ps->hProcess, (LPCVOID)Addr, lpDst, Size, &Read);
|
||||
return Read;
|
||||
}
|
||||
|
||||
SIZE_T ps_write(process_t* ps, ULONG_PTR Addr, LPCVOID lpSrc, SIZE_T Size)
|
||||
{
|
||||
SIZE_T Write;
|
||||
if (ps == ps_this_process)
|
||||
{
|
||||
Write = Size;
|
||||
CopyMemory((LPVOID)Addr, lpSrc, Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!WriteProcessMemory(ps->hProcess, (LPVOID)Addr, lpSrc, Size, &Write))
|
||||
return 0;
|
||||
}
|
||||
return Write;
|
||||
}
|
||||
|
||||
pe_t* ps_get_module(process_t* ps, LPCSTR lpModuleName)
|
||||
{
|
||||
CHAR szModuleName[64];
|
||||
strcpy_s(szModuleName, sizeof(szModuleName), lpModuleName);
|
||||
_strlwr_s(szModuleName,sizeof(szModuleName));
|
||||
|
||||
if (_ps_is_global_module(lpModuleName) && ps != ps_this_process)
|
||||
return ps_get_module(ps_this_process, lpModuleName);
|
||||
|
||||
SIZE_T uNameLen = strlen(szModuleName);
|
||||
for (DWORD i = 0; i < ps->dwModules; i++)
|
||||
{
|
||||
CHAR szCurrentModuleName[64];
|
||||
pe_t* pe = &ps->pModules[i];
|
||||
strcpy_s(szCurrentModuleName, sizeof(szCurrentModuleName), pe->szName);
|
||||
_strlwr_s(szCurrentModuleName,sizeof(szCurrentModuleName));
|
||||
SIZE_T uCurrentNameLen = strlen(szModuleName);
|
||||
if (!memcmp(szCurrentModuleName, szModuleName,
|
||||
min(min(uNameLen,uCurrentNameLen), sizeof(szModuleName))))
|
||||
{
|
||||
return pe;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ULONG_PTR _ps_sig_scan(PCSTR pCode, DWORD dwCodeSize, LPCSTR lpSig, LPCSTR lpMask)
|
||||
{
|
||||
DWORD dwSigLen = (DWORD)strlen(lpMask);
|
||||
for (DWORD i = 0; i < dwCodeSize - dwSigLen; i++)
|
||||
{
|
||||
DWORD j = 0;
|
||||
for (; j < dwSigLen; j++)
|
||||
{
|
||||
if (pCode[i + j] != lpSig[j] && lpMask[j] != '?')
|
||||
break;
|
||||
}
|
||||
if (j == dwSigLen) return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ULONG_PTR ps_sig_scan(process_t* ps, pe_t* mod, LPCSTR lpSig, LPCSTR lpMask)
|
||||
{
|
||||
ULONG_PTR CodeVA = mod->BaseAddress + mod->pNt->OptionalHeader.BaseOfCode;
|
||||
DWORD dwCodeSize = mod->pNt->OptionalHeader.SizeOfCode;
|
||||
PCHAR pCode = (PCHAR)malloc(dwCodeSize);
|
||||
|
||||
ps_read(ps, CodeVA, pCode, dwCodeSize);
|
||||
ULONG_PTR Offset = _ps_sig_scan(pCode, dwCodeSize, lpSig, lpMask);
|
||||
|
||||
free(pCode);
|
||||
return Offset ? CodeVA + Offset : 0;
|
||||
}
|
||||
|
||||
ps_seg_t* ps_load_segment(process_t* ps, pe_t* mod, ULONG_PTR Address, DWORD dwSize)
|
||||
{
|
||||
LPVOID lpData;
|
||||
|
||||
BOOL bIsGlobal = _ps_is_global_module(mod->szName);
|
||||
if (ps == ps_this_process || bIsGlobal)
|
||||
{
|
||||
//Directly "project" segment
|
||||
lpData = (LPVOID)Address;
|
||||
if (bIsGlobal) ps = ps_this_process;
|
||||
}
|
||||
else
|
||||
{
|
||||
lpData = malloc(dwSize);
|
||||
if (!lpData) return NULL;
|
||||
if (ps_read(ps, Address, lpData, dwSize) == 0)
|
||||
return NULL;
|
||||
}
|
||||
ps_seg_t* seg = (ps_seg_t*)malloc(sizeof(ps_seg_t));
|
||||
seg->pProcess = ps;
|
||||
seg->pMod = mod;
|
||||
seg->pSeg = (PCHAR)lpData;
|
||||
seg->dwSegSize = dwSize;
|
||||
seg->dwSegRVA = (DWORD)(Address - mod->BaseAddress);
|
||||
|
||||
return seg;
|
||||
}
|
||||
|
||||
ps_seg_t* ps_load_directory(process_t* ps, pe_t* mod, UINT Dir)
|
||||
{
|
||||
UINT_PTR Addr = mod->BaseAddress + mod->pNt->OptionalHeader
|
||||
.DataDirectory[Dir].VirtualAddress;
|
||||
DWORD dwSize = mod->pNt->OptionalHeader.DataDirectory[Dir].Size;
|
||||
return ps_load_segment(ps, mod, Addr, dwSize);
|
||||
}
|
||||
|
||||
void ps_unload_segment(ps_seg_t* seg)
|
||||
{
|
||||
if (seg->pProcess != ps_this_process)
|
||||
free(seg->pSeg);
|
||||
free(seg);
|
||||
}
|
||||
|
||||
PIMAGE_SECTION_HEADER ps_get_section_header(pe_t* mod, LPCSTR lpSectionName)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)
|
||||
((PCHAR)mod->pNt + sizeof(IMAGE_NT_HEADERS));
|
||||
for (int i = 0; i < mod->pNt->FileHeader.NumberOfSections; i++)
|
||||
{
|
||||
SIZE_T uNameLen = strlen(lpSectionName);
|
||||
if (!memcmp(pSection->Name, lpSectionName, min(uNameLen, 8)))
|
||||
return pSection;
|
||||
pSection++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LPVOID ps_find_section(ps_seg_t* seg, LPCSTR lpSectionName)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER pSection = ps_get_section_header(seg->pMod, lpSectionName);
|
||||
if (!pSection) return NULL;
|
||||
return ps_segment_addr(seg, pSection->VirtualAddress);
|
||||
}
|
||||
|
||||
DWORD ps_section_size(PIMAGE_SECTION_HEADER pSection)
|
||||
{
|
||||
DWORD dwSize = pSection->PointerToRawData
|
||||
? pSection->SizeOfRawData : pSection->Misc.VirtualSize;
|
||||
return ps_round_to_page(dwSize);
|
||||
}
|
||||
|
||||
BOOL ps_is_in_directory(pe_t* pe, UINT Dir, ULONG_PTR Addr)
|
||||
{
|
||||
PIMAGE_DATA_DIRECTORY pDir = &pe->pNt->OptionalHeader.DataDirectory[Dir];
|
||||
ULONG_PTR Start = pe->BaseAddress + pDir->VirtualAddress;
|
||||
ULONG_PTR End = Start + pDir->Size;
|
||||
return (Addr >= Start) && (Addr < End);
|
||||
}
|
||||
|
||||
ULONG_PTR export_get_function(pe_export_t* exp, WORD wOrdinal)
|
||||
{
|
||||
PIMAGE_DATA_DIRECTORY pExportDir = &exp->pMod->pNt->OptionalHeader
|
||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||
PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)
|
||||
ps_directory(exp, IMAGE_DIRECTORY_ENTRY_EXPORT);
|
||||
PDWORD pFunctionRVA = (PDWORD)ps_segment_addr(exp, pExport->AddressOfFunctions);
|
||||
DWORD dwExportEntry = pFunctionRVA[wOrdinal - pExport->Base];
|
||||
ULONG_PTR Addr = exp->pMod->BaseAddress + dwExportEntry;
|
||||
if (ps_is_in_directory(exp->pMod, IMAGE_DIRECTORY_ENTRY_EXPORT, Addr))
|
||||
{
|
||||
//Forwarder RVA
|
||||
CHAR szName[64];
|
||||
|
||||
strcpy_s(szName, sizeof(szName), (LPCSTR)ps_segment_addr(exp,dwExportEntry));
|
||||
LPCSTR lpModuleName = szName;
|
||||
PCHAR pSep = strrchr(szName, '.');
|
||||
if (!pSep) return 0;
|
||||
*pSep = 0;
|
||||
LPCSTR lpFuncName = ++pSep;
|
||||
|
||||
pe_t* fwdMod = ps_get_module(exp->pProcess, lpModuleName);
|
||||
if (!fwdMod) return 0;
|
||||
pe_export_t* fwdExp = export_load(exp->pProcess, fwdMod);
|
||||
//Forward by ordinal or name
|
||||
Addr = export_find_function(fwdExp, lpFuncName);
|
||||
export_unload(fwdExp);
|
||||
}
|
||||
return Addr;
|
||||
}
|
||||
|
||||
ULONG_PTR export_find_function(pe_export_t* exp, LPCSTR lpName)
|
||||
{
|
||||
if (lpName[0] == '#')
|
||||
return export_get_function(exp, (WORD)atoi(lpName + 1));
|
||||
|
||||
PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)
|
||||
ps_directory(exp, IMAGE_DIRECTORY_ENTRY_EXPORT);
|
||||
PDWORD ppNameRVA = (PDWORD)ps_segment_addr(exp, pExport->AddressOfNames);
|
||||
PWORD pOrdinals = (PWORD)ps_segment_addr(exp, pExport->AddressOfNameOrdinals);
|
||||
for (DWORD i = 0; i < pExport->NumberOfNames; i++)
|
||||
{
|
||||
LPSTR lpFuncName = (LPSTR)ps_segment_addr(exp, ppNameRVA[i]);
|
||||
if (!strcmp(lpFuncName, lpName))
|
||||
return export_get_function(exp, (WORD)pExport->Base + pOrdinals[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static pe_reloc_t* reloc_init(ps_seg_t* dataSeg)
|
||||
{
|
||||
if (dataSeg->pMod->pNt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
|
||||
return NULL;
|
||||
PVOID lpReloc = ps_directory(dataSeg, IMAGE_DIRECTORY_ENTRY_BASERELOC);
|
||||
|
||||
pe_reloc_t* rel = (pe_reloc_t*)malloc(sizeof(pe_reloc_t));
|
||||
rel->pData = dataSeg;
|
||||
rel->pBlock = (PIMAGE_BASE_RELOCATION)lpReloc;
|
||||
rel->dwCurrentReloc = 0;
|
||||
|
||||
return rel;
|
||||
}
|
||||
|
||||
pe_reloc_t* reloc_load(process_t* ps, pe_t* mod)
|
||||
{
|
||||
ps_seg_t* dataSeg = ps_load_directory(ps, mod, IMAGE_DIRECTORY_ENTRY_BASERELOC);
|
||||
if (!dataSeg) return NULL;
|
||||
return reloc_init(dataSeg);
|
||||
}
|
||||
|
||||
#define _relocs_count(size) ((size - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD))
|
||||
|
||||
WORD reloc_next(pe_reloc_t* rel)
|
||||
{
|
||||
if (rel->dwCurrentReloc == _relocs_count(rel->pBlock->SizeOfBlock))
|
||||
{
|
||||
rel->pBlock = (PIMAGE_BASE_RELOCATION)((PCHAR)rel->pBlock + rel->pBlock->SizeOfBlock);
|
||||
rel->dwCurrentReloc = 0;
|
||||
}
|
||||
|
||||
if (rel->pBlock == (PIMAGE_BASE_RELOCATION)ps_directory_end(
|
||||
rel->pData, IMAGE_DIRECTORY_ENTRY_BASERELOC))
|
||||
return PS_NO_RELOC;
|
||||
|
||||
return ((PWORD)((PCHAR)rel->pBlock + sizeof(IMAGE_BASE_RELOCATION)))[rel->dwCurrentReloc++];
|
||||
}
|
||||
|
||||
void reloc_unload(pe_reloc_t* rel)
|
||||
{
|
||||
ps_unload_segment(rel->pData);
|
||||
free(rel);
|
||||
}
|
||||
|
||||
pe_import_t* import_load(process_t* ps, pe_t* mod)
|
||||
{
|
||||
pe_import_t* imp = (pe_import_t*)malloc(sizeof(pe_import_t));
|
||||
imp->pImport = ps_load_directory(ps, mod, IMAGE_DIRECTORY_ENTRY_IMPORT);
|
||||
imp->pIAT = ps_load_directory(ps, mod, IMAGE_DIRECTORY_ENTRY_IAT);
|
||||
return imp;
|
||||
}
|
||||
|
||||
BOOL import_find_thunk(pe_import_t* imp, ULONG_PTR ThunkAddr, PCHAR pszLibName, SIZE_T uLibNameLen,
|
||||
PCHAR pszFuncName, SIZE_T uFuncNameLen)
|
||||
{
|
||||
PIMAGE_IMPORT_DESCRIPTOR pDesc = ps_directory(imp->pImport, IMAGE_DIRECTORY_ENTRY_IMPORT);
|
||||
while (pDesc->Characteristics)
|
||||
{
|
||||
PIMAGE_THUNK_DATA pOriginalThunk = (PIMAGE_THUNK_DATA)
|
||||
ps_segment_addr(imp->pImport, pDesc->OriginalFirstThunk);
|
||||
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)
|
||||
ps_segment_addr(imp->pIAT, pDesc->FirstThunk);
|
||||
while (pOriginalThunk->u1.Function)
|
||||
{
|
||||
if ((ULONG_PTR)pThunk == ThunkAddr)
|
||||
{
|
||||
strcpy_s(pszLibName, uLibNameLen, (LPCSTR)
|
||||
ps_segment_addr(imp->pImport, pDesc->Name));
|
||||
if (IMAGE_SNAP_BY_ORDINAL(pOriginalThunk->u1.Ordinal))
|
||||
{
|
||||
sprintf_s(pszFuncName, uFuncNameLen, "#%u",
|
||||
IMAGE_ORDINAL(pOriginalThunk->u1.Ordinal));
|
||||
}
|
||||
else
|
||||
{
|
||||
PIMAGE_IMPORT_BY_NAME pName = (PIMAGE_IMPORT_BY_NAME)
|
||||
ps_segment_addr(imp->pImport, pOriginalThunk->u1.AddressOfData);
|
||||
strcpy_s(pszFuncName, uFuncNameLen, pName->Name);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
pOriginalThunk++;
|
||||
pThunk++;
|
||||
}
|
||||
|
||||
pDesc++;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void import_unload(pe_import_t* imp)
|
||||
{
|
||||
ps_unload_segment(imp->pImport);
|
||||
ps_unload_segment(imp->pIAT);
|
||||
free(imp);
|
||||
}
|
||||
102
ps.h
Normal file
102
ps.h
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
#ifndef __PS_H
|
||||
#define __PS_H
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
typedef struct {
|
||||
ULONG_PTR BaseAddress;
|
||||
PIMAGE_DOS_HEADER pDos;
|
||||
PIMAGE_NT_HEADERS pNt;
|
||||
CHAR szName[64];
|
||||
} pe_t;
|
||||
|
||||
typedef struct {
|
||||
HANDLE hProcess;
|
||||
DWORD dwModules;
|
||||
pe_t* pModules;
|
||||
pe_t* pExe;
|
||||
} process_t;
|
||||
|
||||
//For data or code. Segment of memory
|
||||
typedef struct {
|
||||
process_t* pProcess;
|
||||
pe_t* pMod;
|
||||
//Segment info
|
||||
PCHAR pSeg;
|
||||
DWORD dwSegSize;
|
||||
DWORD dwSegRVA;
|
||||
} ps_seg_t;
|
||||
|
||||
typedef ps_seg_t pe_export_t;
|
||||
|
||||
extern process_t* ps_this_process;
|
||||
extern pe_t* ps_this_module;
|
||||
|
||||
extern DWORD ps_page_size;
|
||||
extern DWORD ps_page_mask;
|
||||
extern DWORD ps_page_power;
|
||||
|
||||
void ps_init();
|
||||
void ps_exit();
|
||||
|
||||
DWORD ps_round_to_page(DWORD dwSize);
|
||||
|
||||
process_t* ps_load_process(DWORD dwPid);
|
||||
void ps_unload_process(process_t* ps);
|
||||
|
||||
SIZE_T ps_read(process_t* ps, ULONG_PTR Addr, LPVOID lpDst, SIZE_T Size);
|
||||
SIZE_T ps_write(process_t* ps, ULONG_PTR Addr, LPCVOID lpSrc, SIZE_T Size);
|
||||
|
||||
pe_t* ps_get_module(process_t* ps, LPCSTR lpModuleName);
|
||||
ULONG_PTR ps_sig_scan(process_t* ps, pe_t* mod, LPCSTR lpSig, LPCSTR lpMask);
|
||||
|
||||
ps_seg_t* ps_load_segment(process_t* ps, pe_t* mod, ULONG_PTR Address, DWORD dwSize);
|
||||
ps_seg_t* ps_load_directory(process_t* ps, pe_t* mod, UINT Dir);
|
||||
void ps_unload_segment(ps_seg_t* seg);
|
||||
#define ps_segment_addr(seg,rva) (PVOID)((PCHAR)seg->pSeg + rva - seg->dwSegRVA)
|
||||
#define ps_directory(seg,dir) ps_segment_addr(seg,seg->pMod->pNt->OptionalHeader.DataDirectory[dir].VirtualAddress)
|
||||
#define ps_directory_size(seg,dir) seg->pMod->pNt->OptionalHeader.DataDirectory[dir].Size
|
||||
#define ps_directory_end(seg,dir) (PVOID)((PCHAR)ps_directory(seg,dir) + ps_directory_size(seg,dir))
|
||||
|
||||
PIMAGE_SECTION_HEADER ps_get_section_header(pe_t* mod, LPCSTR lpSectionName);
|
||||
LPVOID ps_find_section(ps_seg_t* seg, LPCSTR lpSectionName);
|
||||
DWORD ps_section_size(PIMAGE_SECTION_HEADER pSection);
|
||||
BOOL ps_is_in_directory(pe_t* pe, UINT Dir, ULONG_PTR Addr);
|
||||
|
||||
#define ps_load_code(ps,mod) ps_load_segment_class(ps,mod,PS_SEG_CODE)
|
||||
#define ps_unload_code ps_unload_segment
|
||||
#define ps_load_data(ps,mod) ps_load_segment_class(ps,mod,PS_SEG_DATA)
|
||||
#define ps_unload_data ps_unload_segment
|
||||
|
||||
#define ps_load_directory_segment(ps,mod,dir) \
|
||||
ps_load_segment_class(ps,mod,ps_determine_directory_segment(mod,dir)) \
|
||||
|
||||
//#define export_load(ps,mod) ps_load_directory_segment(ps,mod,IMAGE_DIRECTORY_ENTRY_EXPORT)
|
||||
#define export_load(ps,mod) ps_load_directory(ps,mod,IMAGE_DIRECTORY_ENTRY_EXPORT)
|
||||
ULONG_PTR export_get_function(pe_export_t* exp, WORD wOrdinal);
|
||||
ULONG_PTR export_find_function(pe_export_t* exp, LPCSTR lpName);
|
||||
#define export_unload ps_unload_segment
|
||||
|
||||
typedef struct {
|
||||
ps_seg_t* pData;
|
||||
PIMAGE_BASE_RELOCATION pBlock;
|
||||
DWORD dwCurrentReloc;
|
||||
} pe_reloc_t;
|
||||
|
||||
#define PS_NO_RELOC (WORD)-1
|
||||
|
||||
pe_reloc_t* reloc_load(process_t* ps, pe_t* mod);
|
||||
WORD reloc_next(pe_reloc_t* rel);
|
||||
void reloc_unload(pe_reloc_t* rel);
|
||||
|
||||
typedef struct {
|
||||
ps_seg_t* pImport;
|
||||
ps_seg_t* pIAT;
|
||||
} pe_import_t;
|
||||
|
||||
pe_import_t* import_load(process_t* ps, pe_t* mod);
|
||||
BOOL import_find_thunk(pe_import_t* imp, ULONG_PTR ThunkAddr, PCHAR pszLibName, SIZE_T uLibNameLen,
|
||||
PCHAR pszFuncName,SIZE_T uFuncNameLen);
|
||||
void import_unload(pe_import_t* imp);
|
||||
|
||||
#endif
|
||||
201
ps_image.c
Normal file
201
ps_image.c
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
#include "ps_image.h"
|
||||
|
||||
static DWORD _ps_section_flags[PS_IMAGE_SECTIONS] = {
|
||||
PAGE_EXECUTE_READ,
|
||||
PAGE_READWRITE,
|
||||
PAGE_READONLY
|
||||
};
|
||||
|
||||
static DWORD _ps_image_vsec_init_size = PS_DEFAULT_RDATA_RSIZE;
|
||||
|
||||
static BOOL _ps_in_section(ULONG_PTR Base, PIMAGE_SECTION_HEADER pSection, ULONG_PTR Addr)
|
||||
{
|
||||
ULONG_PTR Start = Base + pSection->VirtualAddress;
|
||||
ULONG_PTR End = Start + ps_section_size(pSection);
|
||||
return (Addr >= Start) && (Addr < End);
|
||||
}
|
||||
|
||||
static INT _ps_determine_section(ULONG_PTR Base,PIMAGE_SECTION_HEADER* pHeaders, DWORD dwNum, ULONG_PTR Addr)
|
||||
{
|
||||
for (DWORD i = 0; i < dwNum; i++)
|
||||
{
|
||||
ULONG_PTR Start = Base + pHeaders[i]->VirtualAddress;
|
||||
ULONG_PTR End = Start + ps_round_to_page(pHeaders[i]->SizeOfRawData);
|
||||
if (Addr >= Start && Addr < End)
|
||||
return (INT)i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
ps_image_t* ps_image_create(pe_t* mod, ULONG_PTR VirtualBase,
|
||||
LPCSTR lpCodeSectionName, LPCSTR lpDataSectionName)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER pHeaders[PS_IMAGE_SECTIONS];
|
||||
|
||||
pHeaders[PS_IMAGE_SECTION_CODE] = ps_get_section_header(mod, lpCodeSectionName);
|
||||
pHeaders[PS_IMAGE_SECTION_DATA] = ps_get_section_header(mod, lpDataSectionName);
|
||||
pHeaders[PS_IMAGE_SECTION_RDATA] = NULL;
|
||||
if (!pHeaders[PS_IMAGE_SECTION_CODE] || !pHeaders[PS_IMAGE_SECTION_DATA])
|
||||
return NULL;
|
||||
|
||||
ps_image_t* image = (ps_image_t*)malloc(sizeof(ps_image_t));
|
||||
image->VirtualBase = VirtualBase;
|
||||
image->dwImports = 0;
|
||||
image->import = NULL;
|
||||
|
||||
//Initialize sections
|
||||
image->dwVirtualSize = 0;
|
||||
for (DWORD i = 0; i < PS_IMAGE_SECTIONS; i++)
|
||||
{
|
||||
image->RSec[i].dwRealSize = pHeaders[i]
|
||||
? pHeaders[i]->SizeOfRawData : _ps_image_vsec_init_size;
|
||||
image->RSec[i].pData = (PCHAR)malloc(image->RSec[i].dwRealSize);
|
||||
|
||||
image->VSec[i].dwRVA = image->dwVirtualSize;
|
||||
image->VSec[i].dwSize = ps_round_to_page(image->RSec[i].dwRealSize);
|
||||
image->VSec[i].dwFlags = _ps_section_flags[i];
|
||||
|
||||
if (pHeaders[i])
|
||||
{
|
||||
LPCVOID lpSource = (LPCVOID)(mod->BaseAddress + pHeaders[i]->VirtualAddress);
|
||||
CopyMemory(image->RSec[i].pData, lpSource, image->RSec[i].dwRealSize);
|
||||
}
|
||||
else ZeroMemory(image->RSec[i].pData, image->RSec[i].dwRealSize);
|
||||
|
||||
image->dwVirtualSize += image->VSec[i].dwSize;
|
||||
}
|
||||
|
||||
ULONG_PTR ModBase = mod->BaseAddress;
|
||||
|
||||
#ifndef _WIN64
|
||||
pe_reloc_t* rel = reloc_load(ps_this_process, mod);
|
||||
WORD wReloc;
|
||||
|
||||
pe_import_t* imp = import_load(ps_this_process, mod);
|
||||
CHAR szLibName[64];
|
||||
CHAR szFuncName[64];
|
||||
|
||||
while ((wReloc = reloc_next(rel)) != PS_NO_RELOC)
|
||||
{
|
||||
WORD wType = wReloc >> 12;
|
||||
ULONG_PTR RelocAddr = ModBase + (rel->pBlock->VirtualAddress | (wReloc & 0xFFF));
|
||||
if (wType != IMAGE_REL_BASED_HIGHLOW && wType != IMAGE_REL_BASED_DIR64)
|
||||
continue;
|
||||
INT iSrcSec = _ps_determine_section(ModBase, pHeaders, 2, RelocAddr);
|
||||
if (iSrcSec == -1) continue;
|
||||
|
||||
PULONG_PTR DestAddr = (PULONG_PTR)(image->RSec[iSrcSec].pData +
|
||||
((RelocAddr - pHeaders[iSrcSec]->VirtualAddress) - ModBase));
|
||||
|
||||
if (import_find_thunk(imp, *(PULONG_PTR)RelocAddr, szLibName, sizeof(szLibName),
|
||||
szFuncName, sizeof(szFuncName)))
|
||||
{
|
||||
ps_import_thunk_t* thunk = ps_image_import_add(image, szLibName, szFuncName);
|
||||
*DestAddr = image->VirtualBase + image->VSec[PS_IMAGE_SECTION_RDATA].dwRVA
|
||||
+ (thunk->dwIndex * sizeof(ULONG_PTR));
|
||||
}
|
||||
else
|
||||
{
|
||||
INT iDstSec = _ps_determine_section(ModBase, pHeaders, 2, *(PULONG_PTR)RelocAddr);
|
||||
if (iDstSec == -1) continue;
|
||||
|
||||
*DestAddr = image->VirtualBase + image->VSec[iDstSec].dwRVA
|
||||
+ ((*(PULONG_PTR)RelocAddr - ModBase) - pHeaders[iDstSec]->VirtualAddress);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
reloc_unload(rel);
|
||||
import_unload(imp);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
//ps_image_import_add: Find or create thunk import
|
||||
ps_import_thunk_t* ps_image_import_add(ps_image_t* image, LPCSTR lpLibName, LPCSTR lpFuncName)
|
||||
{
|
||||
ps_import_lib_t* lib = NULL;
|
||||
ps_import_lib_t* lastLib = NULL;
|
||||
|
||||
ps_import_thunk_t* thunk = NULL;
|
||||
ps_import_thunk_t* lastThunk = NULL;
|
||||
|
||||
//Find or create ps_import_lib_t
|
||||
lastLib = image->import;
|
||||
while (lastLib)
|
||||
{
|
||||
SIZE_T uNameLen = strlen(lpLibName);
|
||||
if (!memcmp(lastLib->szLibName, lpLibName,
|
||||
min(uNameLen, sizeof(lastLib->szLibName))))
|
||||
{
|
||||
if (!lib) lib = lastLib;
|
||||
}
|
||||
if (!lastLib->next) break;
|
||||
else lastLib = lastLib->next;
|
||||
}
|
||||
|
||||
if (!lib)
|
||||
{
|
||||
lib = (ps_import_lib_t*)malloc(sizeof(ps_import_lib_t));
|
||||
lib->thunk = NULL;
|
||||
lib->next = NULL;
|
||||
strcpy_s(lib->szLibName, sizeof(lib->szLibName), lpLibName);
|
||||
if (lastLib) lastLib->next = lib;
|
||||
else image->import = lib;
|
||||
}
|
||||
|
||||
//Find or create ps_import_thunk_t
|
||||
lastThunk = lib->thunk;
|
||||
while (lastThunk)
|
||||
{
|
||||
SIZE_T uNameLen = strlen(lpFuncName);
|
||||
if (!memcmp(lastThunk->szFuncName, lpFuncName,
|
||||
min(uNameLen, sizeof(lastThunk->szFuncName))))
|
||||
{
|
||||
if (!thunk) thunk = lastThunk;
|
||||
}
|
||||
if (!lastThunk->next) break;
|
||||
else lastThunk = lastThunk->next;
|
||||
}
|
||||
|
||||
if (!thunk)
|
||||
{
|
||||
thunk = (ps_import_thunk_t*)malloc(sizeof(ps_import_thunk_t));
|
||||
thunk->dwIndex = image->dwImports++;
|
||||
thunk->next = NULL;
|
||||
strcpy_s(thunk->szFuncName, sizeof(thunk->szFuncName), lpFuncName);
|
||||
if (lastThunk) lastThunk->next = thunk;
|
||||
else lib->thunk = thunk;
|
||||
}
|
||||
|
||||
return thunk;
|
||||
}
|
||||
|
||||
static void _ps_image_import_free(ps_import_lib_t* lib)
|
||||
{
|
||||
ps_import_lib_t* libItem = lib;
|
||||
|
||||
while (libItem)
|
||||
{
|
||||
ps_import_thunk_t* thunkItem = libItem->thunk;
|
||||
|
||||
while (thunkItem)
|
||||
{
|
||||
ps_import_thunk_t* thunkNext = thunkItem->next;
|
||||
free(thunkItem);
|
||||
thunkItem = thunkNext;
|
||||
}
|
||||
|
||||
ps_import_lib_t* libNext = libItem->next;
|
||||
free(libItem);
|
||||
libItem = libNext;
|
||||
}
|
||||
}
|
||||
|
||||
void ps_image_free(ps_image_t* image)
|
||||
{
|
||||
_ps_image_import_free(image->import);
|
||||
for (DWORD i = 0; i < PS_IMAGE_SECTIONS; i++)
|
||||
free(image->RSec[i].pData);
|
||||
free(image);
|
||||
}
|
||||
58
ps_image.h
Normal file
58
ps_image.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#ifndef __PS_IMAGE_H
|
||||
#define __PS_IMAGE_H
|
||||
|
||||
#include "ps.h"
|
||||
|
||||
#define PS_DEFAULT_RDATA_RSIZE 4096
|
||||
#define PS_DEFAULT_RDATA_VSIZE 4096
|
||||
|
||||
typedef struct {
|
||||
DWORD dwRVA;
|
||||
DWORD dwSize;
|
||||
DWORD dwFlags;
|
||||
} ps_virtual_section_t;
|
||||
|
||||
typedef struct {
|
||||
PCHAR pData;
|
||||
DWORD dwRealSize;
|
||||
} ps_real_section_t;
|
||||
|
||||
typedef enum {
|
||||
PS_IMAGE_SECTION_CODE = 0, //For all program code
|
||||
PS_IMAGE_SECTION_DATA, //For all program data
|
||||
PS_IMAGE_SECTION_RDATA, //For all service data like IAT
|
||||
PS_IMAGE_SECTIONS
|
||||
} ps_section_type;
|
||||
|
||||
typedef struct ps_import_thunk_s {
|
||||
CHAR szFuncName[64];
|
||||
DWORD dwIndex; //Virtual IAT
|
||||
struct ps_import_thunk_s* next;
|
||||
} ps_import_thunk_t;
|
||||
|
||||
typedef struct ps_import_lib_s {
|
||||
CHAR szLibName[64];
|
||||
ps_import_thunk_t* thunk;
|
||||
struct ps_import_lib_s* next;
|
||||
} ps_import_lib_t;
|
||||
|
||||
typedef struct {
|
||||
//Virtual Image
|
||||
ULONG_PTR VirtualBase;
|
||||
DWORD dwVirtualSize;
|
||||
|
||||
ps_real_section_t RSec[PS_IMAGE_SECTIONS];
|
||||
ps_virtual_section_t VSec[PS_IMAGE_SECTIONS];
|
||||
|
||||
DWORD dwImports; //Virtual IAT import count
|
||||
ps_import_lib_t* import;
|
||||
} ps_image_t;
|
||||
|
||||
ps_image_t* ps_image_create(pe_t* mod,ULONG_PTR VirtualBase,
|
||||
LPCSTR lpCodeSectionName,LPCSTR lpDataSectionName);
|
||||
|
||||
ps_import_thunk_t* ps_image_import_add(ps_image_t* image, LPCSTR lpLibName, LPCSTR lpFuncName);
|
||||
|
||||
void ps_image_free(ps_image_t* image);
|
||||
|
||||
#endif
|
||||
144
ps_inject.c
Normal file
144
ps_inject.c
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
#include "ps_inject.h"
|
||||
#include "ps_image.h"
|
||||
|
||||
int ps_inject(process_t* ps, pe_t* thisMod, LPCSTR lpCodeSec, LPCSTR lpDataSec,
|
||||
LPVOID lpEntryPoint, ps_inject_t* inject)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER pCodeHdr = ps_get_section_header(thisMod, lpCodeSec);
|
||||
PIMAGE_SECTION_HEADER pDataHdr = ps_get_section_header(thisMod, lpDataSec);
|
||||
if (!pCodeHdr || !pDataHdr) return PS_NO_SECTIONS;
|
||||
|
||||
inject->dwCodeSize = ps_section_size(pCodeHdr);
|
||||
inject->dwDataSize = ps_section_size(pDataHdr);
|
||||
inject->dwSize = inject->dwCodeSize + inject->dwDataSize + ps_page_size; //+1 page for PS_IMAGE_RDATA
|
||||
inject->Base = (ULONG_PTR)VirtualAllocEx(ps->hProcess, NULL, inject->dwSize, MEM_RESERVE, PAGE_READWRITE);
|
||||
|
||||
ps_image_t* image = ps_image_create(thisMod, inject->Base, lpCodeSec, lpDataSec);
|
||||
if (!image)
|
||||
{
|
||||
VirtualFreeEx(ps->hProcess, (LPVOID)inject->Base, inject->dwSize, MEM_RELEASE);
|
||||
return PS_CREATE_IMAGE_FAILED;
|
||||
}
|
||||
|
||||
ps_import_lib_t* lib = image->import;
|
||||
while (lib)
|
||||
{
|
||||
ps_import_thunk_t* thunk = lib->thunk;
|
||||
|
||||
pe_t* pLib = ps_get_module(ps, lib->szLibName);
|
||||
if (!pLib) continue;
|
||||
pe_export_t* exp = export_load(ps, pLib);
|
||||
if (!exp) continue;
|
||||
|
||||
while (thunk)
|
||||
{
|
||||
((PULONG_PTR)image->RSec[PS_IMAGE_SECTION_RDATA].pData)[thunk->dwIndex]
|
||||
= export_find_function(exp, thunk->szFuncName);
|
||||
thunk = thunk->next;
|
||||
}
|
||||
|
||||
export_unload(exp);
|
||||
lib = lib->next;
|
||||
}
|
||||
|
||||
for (DWORD i = 0; i < PS_IMAGE_SECTIONS; i++)
|
||||
{
|
||||
DWORD dwOldProtect;
|
||||
ULONG_PTR Addr = image->VirtualBase + image->VSec[i].dwRVA;
|
||||
VirtualAllocEx(ps->hProcess, (LPVOID)Addr, image->VSec[i].dwSize, MEM_COMMIT, PAGE_READWRITE);
|
||||
ps_write(ps, Addr, image->RSec[i].pData, image->RSec[i].dwRealSize);
|
||||
VirtualProtectEx(ps->hProcess, (LPVOID)Addr,
|
||||
image->VSec[i].dwSize, image->VSec[i].dwFlags, &dwOldProtect);
|
||||
}
|
||||
|
||||
inject->dwSize = image->dwVirtualSize;
|
||||
inject->CodeVA = image->VirtualBase + image->VSec[PS_IMAGE_SECTION_CODE].dwRVA;
|
||||
inject->DataVA = image->VirtualBase + image->VSec[PS_IMAGE_SECTION_DATA].dwRVA;
|
||||
inject->EntryPointVA = inject->CodeVA + ((ULONG_PTR)lpEntryPoint
|
||||
- (thisMod->BaseAddress + pCodeHdr->VirtualAddress));
|
||||
|
||||
ps_image_free(image);
|
||||
return PS_INJECT_OK;
|
||||
}
|
||||
|
||||
BOOL ps_adjust_privilege(LPCSTR lpPrivilegeName)
|
||||
{
|
||||
HANDLE hToken;
|
||||
LUID luidPrivilege;
|
||||
TOKEN_PRIVILEGES privileges;
|
||||
|
||||
if (!LookupPrivilegeValue(NULL, lpPrivilegeName, &luidPrivilege))
|
||||
return FALSE;
|
||||
if (!OpenProcessToken(ps_this_process->hProcess, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken))
|
||||
return FALSE;
|
||||
|
||||
privileges.PrivilegeCount = 1;
|
||||
privileges.Privileges[0].Luid = luidPrivilege;
|
||||
privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
AdjustTokenPrivileges(hToken, FALSE, &privileges, sizeof(privileges), NULL, NULL);
|
||||
CloseHandle(hToken);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BYTE _ps_hijack_boot[16];
|
||||
|
||||
#define OP_PUSHFD 0x9C
|
||||
#define OP_PUSHAD 0x60
|
||||
|
||||
#define OP_POPAD 0x61
|
||||
#define OP_POPFD 0x9D
|
||||
|
||||
#define OP_CALL 0xE8
|
||||
#define OP_JMP 0xE9
|
||||
|
||||
#define JMP_OFFSET(from,to) ((to) - (from) - 5)
|
||||
|
||||
BOOL ps_hijack_thread(process_t* ps, DWORD dwTid, ULONG_PTR Code)
|
||||
{
|
||||
CONTEXT Ctx;
|
||||
DWORD dwOldProtect;
|
||||
HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION
|
||||
| THREAD_SUSPEND_RESUME
|
||||
| THREAD_GET_CONTEXT
|
||||
| THREAD_SET_CONTEXT,
|
||||
FALSE, dwTid);
|
||||
if (hThread == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
ZeroMemory(&Ctx, sizeof(CONTEXT));
|
||||
Ctx.ContextFlags = CONTEXT_CONTROL;
|
||||
|
||||
SuspendThread(hThread);
|
||||
GetThreadContext(hThread, &Ctx);
|
||||
|
||||
ULONG_PTR BootCode = (ULONG_PTR)VirtualAllocEx(ps->hProcess, NULL,
|
||||
4096, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
ULONG_PTR PrevAddr = Ctx.Eip;
|
||||
|
||||
//Build shell code
|
||||
_ps_hijack_boot[0] = OP_PUSHFD;
|
||||
_ps_hijack_boot[1] = OP_PUSHAD;
|
||||
|
||||
_ps_hijack_boot[2] = OP_CALL;
|
||||
*(PLONG_PTR)&_ps_hijack_boot[3] = JMP_OFFSET((LONG_PTR)BootCode + 2, (LONG_PTR)Code);
|
||||
|
||||
_ps_hijack_boot[7] = OP_POPAD;
|
||||
_ps_hijack_boot[8] = OP_POPFD;
|
||||
|
||||
_ps_hijack_boot[9] = OP_JMP;
|
||||
*(PLONG_PTR)&_ps_hijack_boot[10] = JMP_OFFSET((LONG_PTR)BootCode + 2, (LONG_PTR)PrevAddr);
|
||||
|
||||
//Write
|
||||
ps_write(ps, BootCode, _ps_hijack_boot, sizeof(_ps_hijack_boot));
|
||||
VirtualProtect((LPVOID)BootCode, sizeof(_ps_hijack_boot), PAGE_EXECUTE_READWRITE, &dwOldProtect);
|
||||
|
||||
//Execute
|
||||
Ctx.Eip = BootCode;
|
||||
|
||||
SetThreadContext(hThread, &Ctx);
|
||||
ResumeThread(hThread);
|
||||
CloseHandle(hThread);
|
||||
return TRUE;
|
||||
}
|
||||
30
ps_inject.h
Normal file
30
ps_inject.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef __PS_INJECT_H
|
||||
#define __PS_INJECT_H
|
||||
|
||||
#include "ps.h"
|
||||
|
||||
#define PS_CREATE_IMAGE_FAILED -2
|
||||
#define PS_NO_SECTIONS -1
|
||||
#define PS_INJECT_OK 0
|
||||
|
||||
typedef struct {
|
||||
//Base of "image" in target process
|
||||
ULONG_PTR Base;
|
||||
DWORD dwSize;
|
||||
|
||||
ULONG_PTR CodeVA;
|
||||
DWORD dwCodeSize;
|
||||
|
||||
ULONG_PTR DataVA;
|
||||
DWORD dwDataSize;
|
||||
|
||||
ULONG_PTR EntryPointVA;
|
||||
} ps_inject_t;
|
||||
|
||||
int ps_inject(process_t* ps, pe_t* thisMod, LPCSTR lpCodeSec, LPCSTR lpDataSec,
|
||||
LPVOID lpEntryPoint,ps_inject_t* inject);
|
||||
|
||||
BOOL ps_adjust_privilege(LPCSTR lpPrivilegeName);
|
||||
BOOL ps_hijack_thread(process_t* ps, DWORD dwTid, ULONG_PTR Code);
|
||||
|
||||
#endif
|
||||
16
ps_target.h
Normal file
16
ps_target.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef __PS_TARGET_H
|
||||
#define __PS_TARGET_H
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#ifndef _WIN64
|
||||
|
||||
#define PS_IMPORT(funcName,thunkName) \
|
||||
__declspec(naked) ULONG_PTR thunkName() \
|
||||
{ \
|
||||
__asm jmp dword ptr ds : [funcName] \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
134
pslib.vcxproj
Normal file
134
pslib.vcxproj
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{AA1B5896-DAB2-4A98-8978-710A51814757}</ProjectGuid>
|
||||
<RootNamespace>pslib</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ps.c" />
|
||||
<ClCompile Include="ps_image.c" />
|
||||
<ClCompile Include="ps_inject.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ps.h" />
|
||||
<ClInclude Include="ps_image.h" />
|
||||
<ClInclude Include="ps_inject.h" />
|
||||
<ClInclude Include="ps_target.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
42
pslib.vcxproj.filters
Normal file
42
pslib.vcxproj.filters
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ps_inject.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ps.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ps_image.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ps_inject.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ps.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ps_image.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ps_target.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Loading…
Add table
Reference in a new issue