[toc]

常用代码段

0x01 GetProcessId-获取进程id

获取进程id

  • CreateToolhelp32Snapshot
  • Process32First
  • Process32Next
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
DWORD processNameToId(LPCTSTR lpszProcessName)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnapshot, &pe)) {
MessageBox(NULL, "The frist entry of the process list has not been copyied to the buffer", "Notice", MB_ICONINFORMATION | MB_OK);
return 0;
}
while (Process32Next(hSnapshot, &pe)) {
if (!strcmp(lpszProcessName, pe.szExeFile)) {
return pe.th32ProcessID;
}
}

return 0;
}
1
2
3
4
5
DWORD dwProcessId = processNameToId(szExeName);
if (dwProcessId == 0) {
MessageBox(NULL, "The target process have not been found !", "Notice", MB_ICONINFORMATION | MB_OK);
return -1;
}

0x04 OpenProcess-打开目标进程

  • OpenProcess
1
2
3
4
5
HANDLE hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (!hTargetProcess) {
MessageBox(NULL, "Open target process failed !", "Notice", MB_ICONINFORMATION | MB_OK);
return 0;
}

0x03 IsWow64-判断目标进程是不是64位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BOOL IsWow64(HANDLE hProcess)
{
typedef BOOL(WINAPI* LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process;

BOOL bIsWow64 = FALSE;
fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
GetModuleHandle("kernel32"), "IsWow64Process");

if (NULL != fnIsWow64Process)
{
fnIsWow64Process(hProcess, &bIsWow64);
}
return bIsWow64;
}

0x04 Is64BitOs-判断当前机器是不是 64bit。

主要用的API为

  • GetNativeSystemInfo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
BOOL Is64BitOS()
{
typedef VOID(WINAPI* LPFN_GetNativeSystemInfo)(__out LPSYSTEM_INFO lpSystemInfo);
LPFN_GetNativeSystemInfo fnGetNativeSystemInfo = (LPFN_GetNativeSystemInfo)GetProcAddress(GetModuleHandle("kernel32"), "GetNativeSystemInfo");
if (fnGetNativeSystemInfo)
{
SYSTEM_INFO stInfo = { 0 };
fnGetNativeSystemInfo(&stInfo);
if (stInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64
|| stInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
{
return TRUE;
}
}
return FALSE;
}

0x05 EnableDebugPriv-本地提权

  • OpenProcessToken
  • LookupPrivilegeValue
  • AdjustTokenPrivileges
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
bool enableDebugPriv()
{
HANDLE hToken;
LUID sedebugnameValue;
TOKEN_PRIVILEGES tkp;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
return false;
}
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)) {
CloseHandle(hToken);
return false;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) {
CloseHandle(hToken);
return false;
}
return true;
}

getProcessAddr-获取目标进程首地址

主要逻辑,获取目标进程的快照,检索第一个模块的信息并返回模块的 modBaseAddr

  • CreateToolhelp32Snapshot:获取指定进程以及这些进程使用的堆、模块和线程的快照。
  • Module32First
  • MODULEENTRY32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//获取目标进程首地址
BOOL CImageBloodDlg::getProcessAddr(DWORD dwPID, DWORD& baseAddr)
{
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;

// 在目标进程中获取所有进程的snapshot
hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
if (hModuleSnap == INVALID_HANDLE_VALUE)
{
AfxMessageBox(_T("CreateToolhelp32Snapshot (of modules) fail"));
return(FALSE);
}

// 设置MODULEENTRY32数据结构大小字段
me32.dwSize = sizeof(MODULEENTRY32);

//检索第一个模块的信息,不成功则返回
if (!Module32First(hModuleSnap, &me32))
{
AfxMessageBox(_T("Module32First fail")); // 显示调用失败
CloseHandle(hModuleSnap); // 清除句柄对象
return(FALSE);
}

// 从me32中得到基址
baseAddr = (DWORD)me32.modBaseAddr;

// 别忘了最后清除模块句柄对象
CloseHandle(hModuleSnap);
return(TRUE);
}

获取PEB

来源:libpeconv/libpeconv/src/peb_lookup.cpp· hasherezade/libpeconv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
inline PPEB get_peb()
{
#if defined(_WIN64)
return (PPEB)__readgsqword(0x60);
#else
return (PPEB)__readfsdword(0x30);
/*
//alternative way to fetch it:
LPVOID PEB = NULL;
__asm {
mov eax, fs:[30h]
mov PEB, eax
};
return (PPEB)PEB;

or:
LPVOID PEB = RtlGetCurrentPeb();
*/
#endif
}

判断磁盘时候开启了写保护

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* @ brief 判断磁盘是否开启了写保护
* @ param wcDrive 磁盘盘符
*/
BOOL IsWriteProtected( TCHAR wcDrive )
{
TCHAR szPath[10] = L"\\\\.\\A:\0";
szPath[4] = wcDrive;

HANDLE hDevice = CreateFile(szPath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0, NULL);

if (hDevice == INVALID_HANDLE_VALUE)
{
return FALSE;
}

BOOL bRet = FALSE;
DWORD dwBytesReturn = 0;
BOOL bWriteable = ::DeviceIoControl(hDevice,
IOCTL_DISK_IS_WRITABLE,
NULL,
0,
NULL,
0,
(LPDWORD) &dwBytesReturn,
NULL);
if (bWriteable)
{
bRet = FALSE;
}
else
{
bRet = ::GetLastError() == ERROR_WRITE_PROTECT ? TRUE:FALSE;
}

::CloseHandle(hDevice);

return bRet;

}

经验

0x01 临时关闭编译告警

1
2
3
4
#pragma warning(push)
#pragma warning(disable:4305)
pCandidate=(VOID PTR_T PTR_T)ModuleSectionInfo.pBase;
#pragma warning(pop)

0x02 修改结构体对齐方式

使用 #pragma pack(1) 之后,结构体最小对齐的字节为1。好处是可以让编译器按照更紧凑的方式存储数据,从而节省内存空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct TestStruct  
{
char a; // 占用1字节
int b; // 占用1字节,与a对齐
double c; // 占用8字节,与b对齐
};

#pragma pack(1)
struct TestPackStruct
{
char a; // 占用1字节
int b; // 占用1字节,与a对齐
double c; // 占用8字节,与b对齐
};
#pragma pack()

/*
TestStruct size:16
TestPackStruct size:13
*/

0x03 未使用的参数、变量

消除未使用参数和结构体警告可以使用下面几个宏:

1
2
3
4
#define UNREFERENCED_PARAMETER(P) {(P) = (P);}
#define UNREFERENCED_LOCAL_VARIABLE(V) {(V) = (V);}
#define DBG_UNREFERENCED_PARAMETER(P) (P)
#define DBG_UNREFERENCED_LOCAL_VARIABLE(V) (V)