以关注并星标🌟 一起学安全❤️
作者:coleak
首发于公号:渗透测试安全攻防
字数:28711
声明:仅供学习参考,请勿用作违法用途
前记
记录最近代码复习的笔记方便查阅,水文一篇
目录
- 窗口程序
- 定时器
- 异步io
- ETW
- SetUnhandledExceptionFilter
- 服务程序
- RPC
- c++
窗口程序
#include <windows.h>
#include<iostream>
#include <commctrl.h> //tools
#include <commctrl.h> // statusbar
//var
#define WM_MY_CUSTOM_MSG (WM_USER + 1)
#define ID_STATUSBAR 6000
#define ID_TOOLBAR 5000
#define IDB_TOOLBAR 101
HWND hEdit;
HWND hListBox;
HWND hResult;
char text[100] = {0};
HWND hStatusBar;
// function
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK CustomDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
void ProcessInput(char* input);
// WinMain
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEXA wc;
HWND hwnd;
MSG msg;
// 定义窗口类
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc; // 窗口过程函数
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "MyWindowClass";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
WNDCLASSA wc3 = { 0 };
wc3.lpfnWndProc = CustomDialogProc; // 设置窗口过程函数
wc3.hInstance = hInstance;
wc3.lpszClassName = "CustomDialog";
wc3.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
if (!RegisterClassA(&wc3)) {
MessageBoxA(NULL, "Window Registration Failed!", "Error", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// 注册窗口类
RegisterClassExA(&wc);
// 创建窗口
hwnd = CreateWindowExA(
0,
"MyWindowClass",
"My First Windows App",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL
);
HWND hButton = CreateWindowExA(
0,
"BUTTON", // 控件类名,固定类
"Click Me", // 按钮上的文字
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
50, 100, 100, 30, // 按钮的大小和位置
hwnd, // 父窗口句柄
(HMENU)1, // 控件的ID
hInstance,
NULL
);
HWND hButton2 = CreateWindowExA(
0,
"BUTTON", // 控件类名,固定类
"Click Me2", // 按钮上的文字
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
100, 200, 200, 60, // 按钮的大小和位置
hwnd, // 父窗口句柄
(HMENU)2, // 控件的ID
hInstance,
NULL
);
hEdit = CreateWindowExA(
0,
"EDIT",
"content",
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT,
350, 300, 300, 90,
hwnd,
(HMENU)3,
hInstance,
NULL
);
hListBox = CreateWindowExA(
0,
"LISTBOX",
NULL,
WS_CHILD | WS_VISIBLE | WS_BORDER | LBS_NOTIFY,
450, 450, 400, 300,
hwnd,
(HMENU)4,
hInstance,
NULL
);
SendMessageA(hListBox, LB_ADDSTRING, 0, (LPARAM)"Item 1");
SendMessageA(hListBox, LB_ADDSTRING, 0, (LPARAM)"Item 2");
SendMessageA(hListBox, LB_ADDSTRING, 0, (LPARAM)"Item 3");
HMENU hMenu = CreateMenu();
AppendMenuA(hMenu, MF_STRING, 1001, "File");
AppendMenuA(hMenu, MF_STRING, 1002, "Edit");
AppendMenuA(hMenu, MF_STRING, 1003, "View");
SetMenu(hwnd, hMenu);
HMENU hHelpMenu = CreateMenu();
AppendMenuA(hHelpMenu, MF_STRING, 1004, "Save");
AppendMenuA(hHelpMenu, MF_STRING, 1005, "New");
// 将子菜单添加到主菜单
AppendMenuA(hMenu, MF_POPUP, (UINT_PTR)hHelpMenu, "FILE");
// 将菜单设置为窗口的菜单
SetMenu(hwnd, hMenu);
HWND hCustomDlg = CreateWindowExA(
WS_EX_DLGMODALFRAME, // 扩展样式,使用对话框边框
"CustomDialog", // 自定义窗口类名
"Custom Dialog", // 标题(可选)
WS_POPUP | WS_VISIBLE | WS_CAPTION, // 窗口样式
CW_USEDEFAULT, CW_USEDEFAULT, 400, 450, // 位置和大小
hwnd, // 父窗口句柄
NULL, // 菜单句柄
hInstance, // 实例句柄
NULL // 额外参数
);
HWND hEdit2 = CreateWindowExA(
0,
"EDIT",
"",
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT,
10, 10, 200, 20,
hCustomDlg,
(HMENU)101,
hInstance,
NULL
);
HWND hButton3 = CreateWindowExA(
0,
"BUTTON",
"OK",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
100, 50, 80, 30,
hCustomDlg,
(HMENU)IDOK,
hInstance,
NULL
);
hResult = CreateWindowExA(0, "STATIC", "Result will be shown here", WS_CHILD | WS_VISIBLE,
1000,540, 100, 100, hwnd, (HMENU)3, hInstance, NULL);
//tools
HWND hToolbar = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL, WS_CHILD | WS_VISIBLE | TBSTYLE_WRAPABLE, 0, 0, 0, 0, hwnd, (HMENU)ID_TOOLBAR, hInstance, NULL);
// 工具栏按钮信息
TBADDBITMAP tbab;
tbab.hInst = HINST_COMMCTRL;
tbab.nID = IDB_STD_SMALL_COLOR;
SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
TBBUTTON tbb[2];
ZeroMemory(tbb, sizeof(tbb));
tbb[0].iBitmap = STD_FILESAVE;
tbb[0].fsState = TBSTATE_ENABLED;
tbb[0].fsStyle = TBSTYLE_BUTTON;
tbb[0].idCommand = 1004;
tbb[1].iBitmap = STD_FILENEW;
tbb[1].fsState = TBSTATE_ENABLED;
tbb[1].fsStyle = TBSTYLE_BUTTON;
tbb[1].idCommand = 1005;
SendMessageA(hToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
SendMessageA(hToolbar, TB_ADDBUTTONSA, sizeof(tbb) / sizeof(TBBUTTON), (LPARAM)&tbb);
//HWND hwnd3 = CreateWindowA("MyWindowClass", "Status Bar Example", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 400, hwnd, NULL, hInstance, NULL);
// 显示窗口
ShowWindow(hCustomDlg, SW_SHOW);
UpdateWindow(hCustomDlg);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// 消息循环
while (GetMessageA(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
return (int)msg.wParam;
}
// 窗口过程函数的定义
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE:
{
// 创建状态栏
hStatusBar = CreateWindowExA(0, STATUSCLASSNAMEA, NULL, WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
0, 0, 0, 0, hwnd, (HMENU)ID_STATUSBAR, GetModuleHandleA(NULL), NULL);
// 设置状态栏的初始文本
SendMessageA(hStatusBar, SB_SETTEXTA, 0, (LPARAM)"Ready");
}
break;
case WM_SIZE:
{
// 调整状态栏的大小和位置
SetWindowPos(hStatusBar, HWND_BOTTOM, 0, 0, 0,0,SWP_NOZORDER | SWP_NOACTIVATE);
}
break;
case WM_MY_CUSTOM_MSG:
SetWindowTextA(hwnd, (LPCSTR)lParam); //主窗口标题
break;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case 1:
RtlZeroMemory(text, 100);
GetWindowTextA(hEdit, text, 100);
MessageBoxA(hwnd, text, "You Entered", MB_OK);
ProcessInput(text);
SetWindowTextA(hResult, text);
break;
case 2:
MessageBoxA(hwnd, "Button2 clicked!", "Event", MB_OK);
break;
case 4:
if (HIWORD(wParam) == LBN_SELCHANGE) {
int index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
RtlZeroMemory(text, 100);
SendMessageA(hListBox, LB_GETTEXT, index, (LPARAM)text);
MessageBoxA(hwnd, text, "You Selected", MB_OK);
}
break;
case 1001:
MessageBoxA(hwnd, "File Menu Clicked", "Menu", MB_OK);
break;
case 1002:
MessageBoxA(hwnd, "Edit Menu Clicked", "Menu", MB_OK);
break;
case 1003:
MessageBoxA(hwnd, "View Menu Clicked", "Menu", MB_OK);
break;
case 1004:
MessageBoxA(hwnd, "Save Menu Clicked", "Menu", MB_OK);
break;
case 1005:
MessageBoxA(hwnd, "New Menu Clicked", "Menu", MB_OK);
break;
default:
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// 在窗口中绘制文本
TextOutA(hdc, 50, 50, "Hello, Windows!", 15);
EndPaint(hwnd, &ps);
break;
}
case WM_KEYDOWN:
switch (wParam) {
case VK_LEFT: // 左箭头键
MessageBoxA(hwnd, "Left arrow key pressed", "Key Event", MB_OK);
break;
case VK_RIGHT: // 右箭头键
MessageBoxA(hwnd, "Right arrow key pressed", "Key Event", MB_OK);
break;
case VK_ESCAPE: // 如果按下了 ESC 键
DestroyWindow(hwnd);
break;
default:
break;
}
case WM_CHAR:
if (wParam == 'a') {
MessageBoxA(hwnd, "You pressed 'a'", "Key Press", MB_OK);
}
break;
case WM_LBUTTONDOWN: {
int x = LOWORD(lParam); // 鼠标点击的X坐标
int y = HIWORD(lParam); // 鼠标点击的Y坐标
char buffer[256];
sprintf_s(buffer, "Mouse clicked at (%d, %d)", x, y);
MessageBoxA(hwnd, buffer, "Mouse Click", 0);
break;
}
default:
return DefWindowProcA(hwnd, msg, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK CustomDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_COMMAND:
if (LOWORD(wParam) == IDOK) {
RtlZeroMemory(text, 100);
GetWindowTextA(GetDlgItem(hDlg, 101), text, 100);
MessageBoxA(hDlg, text, "You Entered", MB_OK);
SendMessageA(GetParent(hDlg), WM_MY_CUSTOM_MSG, 0, (LPARAM)text);
DestroyWindow(hDlg);
}
break;
case WM_CLOSE:
DestroyWindow(hDlg);
break;
default:
return DefWindowProcA(hDlg, message, wParam, lParam);
}
return 0;
}
void ProcessInput(char* input) {
// 示例:将输入字符串转换为大写
int i = 0;
while (input[i] != '�') {
input[i] = toupper(input[i]);
i++;
}
}
PostQuitMessage和DestroyWindow都可以关闭窗口,区别如下:
DestroyWindow
函数直接销毁指定的窗口,并发送一条 WM_DESTROY
消息给该窗口的窗口过程。它会执行以下操作:
-
销毁窗口及其所有子窗口。 -
释放与窗口关联的所有系统资源,如内存、设备上下文等。 -
将窗口从屏幕上移除。 -
发送 WM_DESTROY
消息到窗口过程。
PostQuitMessage
不会直接销毁窗口,而是向消息队列中放置一个 WM_QUIT
消息。它的主要作用是通知消息循环应该终止。WM_QUIT
消息的接收意味着应用程序的消息循环应该结束。
定时器
#include <windows.h>
#include <stdio.h>
#include <time.h>
int current_time1 = 0;
int current_time2 = 0;
int flag = 0;
VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired) {
current_time2=time(NULL);
if (current_time2 - current_time1 ==10)
flag = 1;
}
int main() {
HANDLE hTimer = NULL;
HANDLE hTimerQueue = NULL;
hTimerQueue = CreateTimerQueue();
if (hTimerQueue == NULL) {
printf("CreateTimerQueue failed (%lu)n", GetLastError());
return 1;
}
if (!CreateTimerQueueTimer(&hTimer, hTimerQueue, TimerRoutine, NULL, 10000, 0, 0)) {
printf("CreateTimerQueueTimer failed (%lu)n", GetLastError());
return 1;
}
current_time1= time(NULL);
while (!flag)
{
if (flag)
break;
//junk function
Sleep(1000);
}
//real function
//release Timer
if (hTimerQueue) {
DeleteTimerQueue(hTimerQueue);
}
return 0;
}
异步io
#include <windows.h>
#include <stdio.h>
#define BUFFER_SIZE 50
#define readcount 10
static char buffer[readcount][BUFFER_SIZE];
// 读取完成时的回调函数
void CALLBACK FileIOCompletionRoutine(
DWORD dwErrorCode,
DWORD dwNumberOfBytesTransfered,
LPOVERLAPPED lpOverlapped
) {
if (dwErrorCode != 0) {
printf("I/O operation failed. Error: %lun", dwErrorCode);
return;
}
printf("Asynchronous I/O completed. Bytes transferred: %lun", dwNumberOfBytesTransfered);
}
int main() {
// 打开源文件,启用异步(重叠)I/O
HANDLE hFile = CreateFile(
TEXT("D:\c_project\dlltest\windows\file2.txt"),
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL
);
if (hFile == INVALID_HANDLE_VALUE) {
printf("Failed to open source file. Error: %lun", GetLastError());
return 1;
}
OVERLAPPED ol = { 0 };
ol.hEvent = (HANDLE)hFile; // 将文件句柄存储在 hEvent 字段中,以便在回调函数中使用
int len = 0;
for (int i = 0; i < readcount; i++) {
// 启动异步读取操作
BOOL result = ReadFileEx(
hFile, // 文件句柄
buffer[i], // 数据缓冲区
BUFFER_SIZE, // 要读取的字节数
&ol, // OVERLAPPED 结构
FileIOCompletionRoutine // 回调函数
);
len += BUFFER_SIZE;
ol.Offset = len;
//SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
if (!result) {
printf("Failed to start async read. Error: %lun", GetLastError());
CloseHandle(hFile);
return 1;
}
}
// 主线程执行其他任务
for (int i = 0; i < 10; i++) {
printf("Main thread is working... %dn", i);
}
// 等待所有异步操作完成
SleepEx(INFINITE, TRUE);
CloseHandle(hFile);
return 0;
}
ETW
机制简介
简单介绍四层结构:providers采集数据,sessions收集来自一个或多个providers的数据,controller负责控制sessions,session将从providers采集的数据发送到consumer
查询系统中的providers和session
logman query providers #基于注册表且有二进制文件
logman query providers Microsoft-Windows-Kernel-Process
logman query -ets #sessions
logman query "EventLog-Application" -ets #providers具体信息
tasklist|findstr MsMpEng
logman query providers -pid 8556
logman create trace spotless-tracing -ets
logman query -ets |findstr spotless-tracing
logman query spotless-tracing -ets
logman update spotless-tracing -p Microsoft-Windows-Kernel-Process 0x50 -ets
logman query spotless-tracing -ets
logman update trace spotless-tracing --p Microsoft-Windows-Kernel-Process 0x50 -ets
logman stop spotless-tracing -ets
logman query -ets |findstr spotless-tracing
c# API
using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.Parsers;
using Microsoft.Diagnostics.Tracing.Session;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SimpleKernelConsumer
{
class ProcessInfo
{
public int Id { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
var processes = Process.GetProcesses().Select(p => new ProcessInfo
{
Name = p.ProcessName,
Id = p.Id
}).ToDictionary(p => p.Id);
using (var session = new TraceEventSession(Environment.OSVersion.Version.Build >= 9200 ? "MyKernelSession" : KernelTraceEventParser.KernelSessionName))
{
session.EnableKernelProvider(KernelTraceEventParser.Keywords.Process | KernelTraceEventParser.Keywords.ImageLoad);
var parser = session.Source.Kernel;
parser.ProcessStart += e => {
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"{e.TimeStamp}.{e.TimeStamp.Millisecond:D3}: Process {e.ProcessID} ({e.ProcessName}) Created by {e.ParentID}: {e.CommandLine}");
processes.Add(e.ProcessID, new ProcessInfo { Id = e.ProcessID, Name = e.ProcessName });
};
parser.ProcessStop += e => {
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"{e.TimeStamp}.{e.TimeStamp.Millisecond:D3}: Process {e.ProcessID} {TryGetProcessName(e)} Exited");
};
parser.ImageLoad += e => {
Console.ForegroundColor = ConsoleColor.Yellow;
var name = TryGetProcessName(e);
Console.WriteLine($"{e.TimeStamp}.{e.TimeStamp.Millisecond:D3}: Image Loaded: {e.FileName} into process {e.ProcessID} ({name}) Size=0x{e.ImageSize:X}");
};
parser.ImageUnload += e => {
Console.ForegroundColor = ConsoleColor.DarkYellow;
var name = TryGetProcessName(e);
Console.WriteLine($"{e.TimeStamp}.{e.TimeStamp.Millisecond:D3}: Image Unloaded: {e.FileName} from process {e.ProcessID} ({name})");
};
Task.Run(() => session.Source.Process());
Thread.Sleep(TimeSpan.FromSeconds(60));
}
string TryGetProcessName(TraceEvent evt)
{
if (!string.IsNullOrEmpty(evt.ProcessName))
return evt.ProcessName;
return processes.TryGetValue(evt.ProcessID, out var info) ? info.Name : string.Empty;
}
}
}
}
reference
https://renyili.org/post/etw_study/
https://www.cnblogs.com/Icys/p/EtwProcess.html
https://www.zhangshengrong.com/p/AvN6Y0WBam/
https://xz.aliyun.com/t/12730?time__1311=GqGxu7G%3DGQ9DlrzG7DynFai%3DLz4iTPpD
https://blog.mozilla.org/sfink/tag/etw/
https://www.preludesecurity.com/blog/event-tracing-for-windows-etw-your-friendly-neighborhood-ipc-mechanism
https://blog.trailofbits.com/2023/11/22/etw-internals-for-security-research-and-forensics/
https://blog.palantir.com/tampering-with-windows-event-tracing-background-offense-and-defense-4be7ac62ac63
https://www.meziantou.net/listing-all-available-etw-events-in-a-dotnet-application.htm
https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/etw-event-tracing-for-windows-101
SetUnhandledExceptionFilter
#include <windows.h>
#include <dbghelp.h>
#include <iostream>
// 异常处理函数
LONG WINAPI WriteDumpHandler(EXCEPTION_POINTERS* pExceptionPointers) {
// 打开或创建一个dump文件
HANDLE hFile = CreateFile(L"dumpfile.dmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
// 写入dump信息
MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
dumpInfo.ThreadId = GetCurrentThreadId();
dumpInfo.ExceptionPointers = pExceptionPointers;
dumpInfo.ClientPointers = FALSE;
MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
hFile,
MiniDumpNormal,
&dumpInfo,
NULL,
NULL
);
CloseHandle(hFile);
std::cout << "Dump file created." << std::endl;
} else {
std::cout << "Failed to create dump file." << std::endl;
}
return EXCEPTION_EXECUTE_HANDLER; // 告诉系统异常已处理
}
int main() {
// 设置未处理异常过滤器
SetUnhandledExceptionFilter(WriteDumpHandler);
// 故意制造一个异常
int* p = nullptr;
*p = 42; // 访问冲突异常
return 0;
}
SetUnhandledExceptionFilter
是 Windows API 中的一个函数,用于指定一个全局的异常处理函数(也叫未处理异常过滤器),主要用于清理资源或者记录错误日志等。当应用程序发生未处理的异常(如访问冲突、非法指令等)时,系统会调用这个函数,故障处后面的代码不会再执行,可以windbg分析dmp
!analyze -v
.ecxr
这里简单介绍一下它和veh以及seh的调用顺序
VEH 处理器在 SEH(结构化异常处理)之前被调用,而
SetUnhandledExceptionFilter
设置的处理函数在 SEH 处理程序链的末尾被调用,即在所有 SEH 处理程序之后
举个栗子
#include <windows.h>
#include <stdio.h>
int flag = 0;
// VEH 处理函数
LONG WINAPI Veh(EXCEPTION_POINTERS* ExceptionInfo) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO) {
printf("VEH Handler: Exception code: 0x%xn", ExceptionInfo->ExceptionRecord->ExceptionCode);
flag = 1;
return EXCEPTION_CONTINUE_EXECUTION; // 处理异常后,继续执行
}
// 如果不是访问违例异常,返回 EXCEPTION_CONTINUE_SEARCH,交给下一个处理程序(包括 SEH 和 SetUnhandledExceptionFilter)
return EXCEPTION_CONTINUE_SEARCH;
}
// 未处理异常过滤器
LONG WINAPI UnhandledException(EXCEPTION_POINTERS* ExceptionInfo) {
printf("UnhandledExceptionFilter: Exception code: 0x%xn", ExceptionInfo->ExceptionRecord->ExceptionCode);
// 处理其他未处理的异常
return EXCEPTION_EXECUTE_HANDLER; // 标记为已处理异常
}
int main() {
// 注册 VEH 处理器
AddVectoredExceptionHandler(1, Veh);
// 设置未处理异常过滤器
SetUnhandledExceptionFilter(UnhandledException);
int a = 1;
int result = a / flag; // 这将引发除零异常
// 触发异常
int* p = NULL;
*p = 0; // 引发访问违例异常
return 0;
}
VEH Handler: Exception code: 0xc0000094 UnhandledExceptionFilter: Exception code: 0xc0000005
这里先在veh中处理,veh处理不了再到seh,最后交给SetUnhandledExceptionFilter设置的捕获函数处理
服务程序
#include <windows.h>
#include <stdio.h>
// 服务名称
#define SERVICE_NAME "MySimpleService"
// 全局变量
SERVICE_STATUS g_ServiceStatus;
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
FILE* fp;
// 函数声明
void WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
void WINAPI ServiceCtrlHandler(DWORD);
void ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
int main(int argc, char* argv[]) {
SERVICE_TABLE_ENTRYA ServiceTable[] = {
{ (LPSTR)SERVICE_NAME, (LPSERVICE_MAIN_FUNCTIONA)ServiceMain },
{ NULL, NULL }
};
// 连接到SCM并运行服务
if (StartServiceCtrlDispatcherA(ServiceTable) == FALSE) {
printf("StartServiceCtrlDispatcherA failed (%d)n", GetLastError());
return GetLastError();
}
return 0;
}
// 服务主函数
void WINAPI ServiceMain(DWORD argc, LPTSTR* argv) {
g_StatusHandle = RegisterServiceCtrlHandlerA(SERVICE_NAME, ServiceCtrlHandler);
if (g_StatusHandle == NULL) {
return;
}
fopen_s(&fp, "C:\MyServiceLog.txt", "a");
// 初始化服务状态
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
// 创建事件以指示服务停止
g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_ServiceStopEvent == NULL) {
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
return;
}
// 报告服务已启动
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
// 服务的工作循环
while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0) {
// 模拟工作(记录日志)
if (fp) {
SYSTEMTIME time;
GetLocalTime(&time);
fprintf(fp, "Service running at %02d:%02d:%02dn", time.wHour, time.wMinute, time.wSecond);
}
Sleep(3000); // 等待3秒
}
// 服务即将停止
fclose(fp);
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
}
// 控制处理函数
void WINAPI ServiceCtrlHandler(DWORD CtrlCode) {
switch (CtrlCode) {
case SERVICE_CONTROL_STOP:
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
SetEvent(g_ServiceStopEvent);
break;
default:
break;
}
}
// 报告服务状态
void ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) {
static DWORD dwCheckPoint = 1;
g_ServiceStatus.dwCurrentState = dwCurrentState;
g_ServiceStatus.dwWin32ExitCode = dwWin32ExitCode;
g_ServiceStatus.dwWaitHint = dwWaitHint;
if (dwCurrentState == SERVICE_START_PENDING)
g_ServiceStatus.dwControlsAccepted = 0;
else
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
if (dwCurrentState == SERVICE_RUNNING || dwCurrentState == SERVICE_STOPPED)
g_ServiceStatus.dwCheckPoint = 0;
else
g_ServiceStatus.dwCheckPoint = dwCheckPoint++;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
}
测试服务
sc create MySimpleService binPath= "D:c_projectdlltestx64Debugwindows.exe"
sc start MySimpleService
sc stop MySimpleService
sc delete MySimpleService
RPC
RPC/socket对比
RPC(Remote Procedure Call): RPC属于应用层协议。它通过模拟本地函数调用,使得远程函数调用像本地调用一样透明。程序员不需要关心底层通信细节,只需要调用远程提供的接口,系统会自动处理底层网络通信。
Socket: Socket是一个更底层的通信方式,通常用于传输控制协议(TCP)或用户数据报协议(UDP)等传输层协议。使用Socket编程时,程序员需要显式地管理连接、数据发送和接收等操作。
python实现
import xmlrpc.client
# 连接到RPC服务器
proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
# 调用远程函数
result_add = proxy.add(5, 3)
result_multiply = proxy.multiply(5, 3)
# 输出结果
print(f"The result of add(5, 3) is: {result_add}")
print(f"The result of multiply(5, 3) is: {result_multiply}")
import xmlrpc.client
# 连接到RPC服务器
proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
# 调用远程函数
result_add = proxy.add(5, 3)
result_multiply = proxy.multiply(5, 3)
# 输出结果
print(f"The result of add(5, 3) is: {result_add}")
print(f"The result of multiply(5, 3) is: {result_multiply}")
c++
STL
vector
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec(5); // 定义一个存储int类型的vector
vec.push_back(10); // 添加元素
vec.push_back(20);
vec.push_back(30);
vec.resize(15);
std::cout << "Vector elements: ";
for (int i = 0; i < vec.size(); i++) {
std::cout << vec[i] << " "; // 访问并输出每个元素
}
std::cout << std::endl;
vec.pop_back(); // 移除最后一个元素
std::cout << "After pop_back, size: " << vec.size() << std::endl; // 输出vector大小
vec.clear(); // 清空vector
if (vec.empty()) {
std::cout << "Vector is now empty." << std::endl;
}
return 0;
}
list
#include <iostream>
#include <list>
int main() {
std::list<int> lst(5); // 定义一个存储int类型的list
lst.push_back(10); // 在末尾添加元素
lst.push_back(20);
lst.push_back(30);
lst.push_front(5); // 在开头添加元素
std::cout << "List elements: ";
for (std::list<int>::iterator it = lst.begin(); it != lst.end(); ++it) {
std::cout << *it << " "; // 访问并输出每个元素
}
std::cout << std::endl;
lst.pop_front();
lst.pop_back(); // 移除最后一个元素
std::cout << "After pop_back, size: " << lst.size() << std::endl; // 输出list大小
lst.clear(); // 清空list
if (lst.empty()) {
std::cout << "List is now empty." << std::endl;
}
return 0;
}
string
#include <iostream>
#include <string>
int main() {
std::string str = "Hello,World!";
// 修改字符串
str.replace(7, 2, "C++++++++++++++++++++"); // 将 "World" 替换为 "C++"
std::cout << str << std::endl; // 输出 "Hello,WC++++++++++++++++++++ld!"
// 获取子串
std::string sub = str.substr(7, 5);
std::cout << "Substring: " << sub+sub << std::endl; // 输出 "C++++C++++"
// 查找字符
std::size_t pos = str.find("C++");
if (pos != std::string::npos) {
std::cout << "'C++' found at position: " << pos << std::endl;
}
return 0;
}
map
#include <iostream>
#include <map>
int main() {
std::map<int, std::string> map1;
// 插入元素
map1[1] = "One";
map1[2] = "Two";
map1.insert(std::make_pair(3, "Three"));
// 访问和查找元素
std::cout << "Element at key 1: " << map1[1] << std::endl;
auto it = map1.find(2);
if (it != map1.end()) {
std::cout << "Found: " << it->second << std::endl;
}
// 遍历 map
std::cout << "Map contents:" << std::endl;
for (auto it = map1.begin(); it != map1.end(); ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}
// 删除元素
map1.erase(2);
std::cout << "After erasing key 2, size: " << map1.size() << std::endl;
std::cout << "Map contents:" << std::endl;
for (auto it = map1.begin(); it != map1.end(); ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}
return 0;
}
set
#include <iostream>
#include <set>
int main() {
std::set<int> set1 = { 3, 1, 4, 1, 5, 9 };
// 插入元素
set1.insert(6);
set1.insert(2);
// 查找元素
auto it = set1.find(5);
if (it != set1.end()) {
std::cout << "Found: " << *it << std::endl;
}
// 遍历 set
std::cout << "Set elements: ";
for (auto it = set1.begin(); it != set1.end(); ++it) {
std::cout << *it << " "; // 输出 "1 2 3 4 5 6 9"
}
std::cout << std::endl;
// 删除元素
set1.erase(4);
std::cout << "After erasing 4, size: " << set1.size() << std::endl;
return 0;
}
new/delete
#include <iostream>
class Person {
public:
std::string name;
Person(std::string name) : name(name) {
std::cout << "Constructor called for " << name << std::endl;
}
~Person() {
std::cout << "Destructor called for " << name << std::endl;
}
};
int main() {
// 使用 new 分配一个包含 3 个 Person 对象的数组
Person* people = new Person[3] { {"Alice"}, {"Bob"}, {"Charlie"} };
// 打印每个人的名字
for (int i = 0; i < 3; i++) {
std::cout << "Person " << i + 1 << ": " << people[i].name << std::endl;
}
// 释放数组的内存
delete[] people;
return 0;
}
运算符重载
#include <iostream>
class Complex {
private:
double real;
double imag;
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
// 重载一元负号运算符
Complex operator-() const {
return Complex(-real, -imag);
}
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
friend std::ostream& operator<<(std::ostream& os, const Complex& c) {
os << "(" << c.real << " + " << c.imag << "i)";
return os;
}
};
int main() {
Complex c1(3.0, 4.0);
Complex c2 = -c1; // 使用重载的 - 运算符
Complex c3 = c1 + c2;
std::cout << c2<<std::endl;
std::cout << c3;
return 0;
}
模板
#include <iostream>
// 定义一个类模板,用于存储固定大小的数组
template <typename T, int size>
class Array {
private:
T arr[size];
public:
void set(int index, T value) {
if (index >= 0 && index < size) {
arr[index] = value;
}
}
T get(int index) const {
if (index >= 0 && index < size) {
return arr[index];
}
return T(); // 返回默认值
}
int getSize() const {
return size;
}
};
template <typename T>
T getMax(T a, T b) {
return (a > b) ? a : b;
}
int main() {
Array<int, 5> intArray; // 使用 int 类型和大小为 5 的数组
intArray.set(0, 10);
intArray.set(1, 20);
std::cout << "Element at index 0: " << intArray.get(0) << std::endl; // 输出: 10
std::cout << "Element at index 1: " << intArray.get(1) << std::endl; // 输出: 20
std::cout << "Array size: " << intArray.getSize() << std::endl; // 输出: 5
int x = 10, y = 20;
std::cout << "Max of x and y: " << getMax(x, y) << std::endl; // 输出: 20
return 0;
}
封装、继承、多态
#include <iostream>
class Animal {
private:
std::string name; // 封装:将数据成员设为private,外部不能直接访问
public:
// 构造函数
Animal(const std::string& name) : name(name) {}
// 公开的接口,用于获取名字
std::string getName() const {
return name;
}
// 公开的接口,用于设置名字
void setName(const std::string& newName) {
name = newName;
}
// 虚函数,用于展示多态性
virtual void speak() const {
//std::cout << name << " makes a sound." << std::endl;
}
};
class Dog : public Animal { // Dog类继承自Animal类
public:
Dog(const std::string& name) : Animal(name) {}
// 重写父类的虚函数
void speak() const override {
std::cout << getName() << " barks." << std::endl;
}
};
class Cat : public Animal { // Cat类继承自Animal类
public:
Cat(const std::string& name) : Animal(name) {}
// 重写父类的虚函数
void speak() const override {
std::cout << getName() << " meows." << std::endl;
}
};
int main() {
Dog* myDog = new Dog("Buddy");
Animal* myCat = new Cat("Whiskers");
myDog->speak(); // 输出: Buddy barks.
myCat->speak(); // 输出: Whiskers meows.
delete myDog;
delete myCat;
return 0;
}
传值/引用
传值 (const std::string name
):会发生一次字符串的拷贝操作,导致额外的性能开销,尤其是对于较大的字符串。
传引用 (const std::string& name
):直接引用传入的字符串对象,避免了不必要的拷贝操作,更加高效。
原文始发于微信公众号(渗透测试安全攻防):【c/c++ 】Windows 开发笔记[二]
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论