windows 显示进程地址空间
windows 显示进程地址空间
windows 显示进程地址空间
文章目录
- windows 显示进程地址空间
- 显示进程地址空间
显示进程地址空间
/*
3-ProcessInfo.cpp
显示进程地址空间
*/#include "..\\CommonFiles\\CmnHdr.h"
#include "..\\CommonFiles\\Toolhelp.h"#include "resource.h"
#include <windowsx.h>
#include <stdarg.h>
#include <stdio.h>#include <winternl.h> //用于windows内部声明
#include <AclAPI.h> //用于ACL(访问控制器列表)管理
#include <Shlwapi.h> //用于windows shell strFormatKBSize.
#include <ShlObj.h> //为IsUserAnAdmin测试当前用户是否是管理员组的成员。
#include <AclAPI.h> //用于ACL/ACE函数#include <tchar.h>
#include <strsafe.h>#pragma comment (lib,"shlwapi.lib")//shell 轻型使用工具函数库
#pragma comment (lib,"shell32.lib")//
//NTQueryInformationProcess在winternl.h中定义
typedef NTSTATUS(CALLBACK* PFN_NTQUERYINFORMATIONPROCESS)(HANDLE ProcessHandle,PROCESSINFOCLASS ProcessInformationClass,PVOID ProcessInformation,ULONG ProcessInformationLength,PULONG ReturnLength OPTIONAL);typedef struct
{DWORD Filler[4];DWORD InfoBlockAddress;
}__PEB;typedef struct
{DWORD Filler[17];DWORD wszCmdLineAddress;
}__INFOBLOCK;//
/*
PEB(process Environment Block)是一个未公开的结构体
typedef struct _PEB{BYTE Reserved1[2];//2字节BYTE BeingDegged; //1BYTE Reserved2[1];//1PVOID Reserved3[2]//2*4=8PPED_LDR_DATA Ldr; //4PRTL_USER_PROCESS_PARAMETERS ProcessParamters;BYTE Reserved4[104];PVOID Reserved5[52];PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;BYTE Reserved6[128];PVOID Reserved7[1];ULONG SessionId;}PEB,*PPEB;typedef struct _RTL_USER_PROCESS_PARAMETERS{BYTE Reserved1[16];16字节PVOID Reserved2[10];UNICODE_STRING ImagePathName;UNICODE_STRING CommandLine;}RTL_USER_PROCESS_PARAMETERS,*PRTL_USER_PROCESS_PARAMETERS}
*/
//全局变量
//指示由GetTokenInformation函数查询的令牌的提升类型
TOKEN_ELEVATION_TYPE s_elevationType = TokenElevationTypeDefault;
BOOL s_bIsAdmin = FALSE;//是否未管理员
const int s_cchAddress = sizeof(PVOID) * 2;
//函数原型
INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
BOOL Dlg_OnSize(HWND hwnd, UINT state, int cx, int cy);
void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtrl, UINT codeNotify);
DWORD StartElevatedProcess(LPCTSTR szExecutable, LPCTSTR szCmdLine);
BOOL GetProcessElevation(TOKEN_ELEVATION_TYPE* pElevationType, BOOL* pIsAdmin);
VOID ShowModeleInfo(HWND hwnd, PCTSTR pszModulePath);
VOID ShowProcessInfo(HWND hwnd, DWORD dwProcessID);
VOID FormatSizeInKB(DWORD dwSize, DWORD nCharacters,LPTSTR szSize,size_t cchSize);BOOL GetProcessOwner(DWORD PID, LPTSTR szOwner, DWORD cchSize);
BOOL GetProcessOwner(HANDLE hProcess, LPTSTR szOwner, size_t cchSize);
BOOL GetProcessCmdLine(DWORD PID, LPTSTR szCmdLine, DWORD Size);
BOOL GetProcessCmdLine(HANDLE hProcess, LPTSTR szCmdLine, DWORD Size);
NTSTATUS _NtQueryInformationProcess(HANDLE hProcess, PROCESSINFOCLASS pic,PVOID pPI, ULONG cbSize, PULONG pLength);VOID Dlg_PopulateModuleList(HWND hwnd);
VOID Dlg_PopulateProcessList(HWND hwnd);
BOOL GetProcessIntegrityLevel(DWORD PID, PDWORD pIntegrityLevel,PDWORD pPolicy, PDWORD pResourceIntegrityLevel, PDWORD pResourcePolicy);
BOOL GetProcessIntegrityLevel(HANDLE hProcess, PDWORD pIntegrityLevel,PDWORD pPolicy, PDWORD pResourceIntegrityLevel, PDWORD pResourcePolicy);
void AddText(HWND hwnd, PCTSTR pszFormat, ...);
PVOID GetModulePreferredBaseAddr(DWORD dwProcessId, PVOID pvModuleRemote);BOOL GetProcessOwner(HANDLE hProcess, LPTSTR szOwner, size_t cchSize) {// Sanity checksif ((szOwner == NULL) || (cchSize == 0))return(FALSE);// Default valueszOwner[0] = TEXT('\0');// Gget process tokenHANDLE hToken = NULL;CToolhelp::EnablePrivilege(SE_TCB_NAME, TRUE);if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {CToolhelp::EnablePrivilege(SE_TCB_NAME, FALSE);return(FALSE);}// Obtain the size of the user information in the token.DWORD cbti = 0;GetTokenInformation(hToken, TokenUser, NULL, 0, &cbti);// Call should have failed due to zero-length buffer.if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {// Allocate buffer for user information in the token.PTOKEN_USER ptiUser =(PTOKEN_USER)HeapAlloc(GetProcessHeap(), 0, cbti);if (ptiUser != NULL) {// Retrieve the user information from the token.if (GetTokenInformation(hToken, TokenUser, ptiUser, cbti, &cbti)) {SID_NAME_USE snu;TCHAR szUser[MAX_PATH];DWORD chUser = MAX_PATH;PDWORD pcchUser = &chUser;TCHAR szDomain[MAX_PATH];DWORD chDomain = MAX_PATH;PDWORD pcchDomain = &chDomain;// Retrieve user name and domain name based on user's SID.if (LookupAccountSid(NULL,ptiUser->User.Sid,szUser,pcchUser,szDomain,pcchDomain,&snu)) {// build the owner string as \\DomainName\UserName_tcscpy_s(szOwner, cchSize, TEXT("\\\\"));_tcscat_s(szOwner, cchSize, szDomain);_tcscat_s(szOwner, cchSize, TEXT("\\"));_tcscat_s(szOwner, cchSize, szUser);}}// Don't forget to free memory bufferHeapFree(GetProcessHeap(), 0, ptiUser);}}// Don't forget to free process tokenCloseHandle(hToken);// Restore privilegesCToolhelp::EnablePrivilege(SE_TCB_NAME, TRUE);return(TRUE);
}BOOL GetProcessOwner(DWORD PID, LPTSTR szOwner, DWORD cchSize) {// Sanity checksif ((PID <= 0) || (szOwner == NULL))return(FALSE);// Check if we can get information for this processHANDLE hProcess =OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, PID);if (hProcess == NULL)return(FALSE);BOOL bReturn = GetProcessOwner(hProcess, szOwner, cchSize);// Don't forget to release the process handleCloseHandle(hProcess);return(bReturn);
}NTSTATUS _NtQueryInformationProcess(HANDLE hProcess,PROCESSINFOCLASS pic,PVOID pPI,ULONG cbSize,PULONG pLength
) {HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll"));if (hNtDll == NULL) {return(-1);}NTSTATUS lStatus = -1; // error by default.// Note that function name is not UNICODEPFN_NTQUERYINFORMATIONPROCESS pfnNtQIP =(PFN_NTQUERYINFORMATIONPROCESS)GetProcAddress(hNtDll, "NtQueryInformationProcess");if (pfnNtQIP != NULL) {lStatus = pfnNtQIP(hProcess, pic, pPI, cbSize, pLength);}FreeLibrary(hNtDll);return(lStatus);
}///
int WINAPI _tWinMain(HINSTANCE hInstanceExe, HINSTANCE, PTSTR pszCmdLine, int)
{//打开调试权限以运行应用程序查看服务应用CToolhelp::EnablePrivilege(SE_DEBUG_NAME, TRUE);//打开访问SACL权限--访问控制权限CToolhelp::EnablePrivilege(SE_SECURITY_NAME, TRUE);//显示主窗口DialogBox(hInstanceExe, MAKEINTRESOURCE(IDD_PROCESSINFO), NULL, Dlg_Proc);CToolhelp::EnablePrivilege(SE_SECURITY_NAME, FALSE);CToolhelp::EnablePrivilege(SE_DEBUG_NAME, FALSE);return (0);
}INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{switch (uMsg){chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);chHANDLE_DLGMSG(hwnd, WM_SIZE, Dlg_OnSize);chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);}return(FALSE);
}BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{chSETDLGICONS(hwnd, IDI_PROCESSINFO);//当提升权限或者禁用UAC时吗,管理员特权被设置为TRUEBOOL bCanReadSystemProcesses = FALSE;//显示是否正在运行“Filter Token”if (GetProcessElevation(&s_elevationType,&s_bIsAdmin)){//提升标题的前缀TCHAR szTitle[64];switch (s_elevationType){//默认用户活禁用UACcase TokenElevationTypeDefault:if (IsUserAnAdmin()){_tcscpy_s(szTitle, _countof(szTitle), TEXT("Default Administrator"));bCanReadSystemProcesses = TRUE;}else{_tcscpy_s(szTitle, _countof(szTitle), TEXT("Default: "));}break;//进程权限被提升成功case TokenElevationTypeFull:if (IsUserAnAdmin()){_tcscpy_s(szTitle, _countof(szTitle), TEXT("Elevated Administorator"));bCanReadSystemProcesses = TRUE;}else{_tcscpy_s(szTitle, _countof(szTitle), TEXT("Elevated: "));}break;//进程运行与受限(筛选令牌)下case TokenElevationTypeLimited:if (s_bIsAdmin){_tcscpy_s(szTitle, _countof(szTitle), TEXT("Filtered Administrator"));}else{_tcscpy_s(szTitle, _countof(szTitle), TEXT("Filtered: "));}break;}//根据提示类型更新对话框标题GetWindowText(hwnd, _tcschr(szTitle, TEXT('\0')),_countof(szTitle) - _tcslen(szTitle));SetWindowText(hwnd, szTitle);//增加“循牌”图标,以运行用户以提升的权限来运行程序if (!bCanReadSystemProcesses){Button_SetElevationRequiredState(GetDlgItem(hwnd, IDC_BTN_SYSTEM_PROCESSES),!bCanReadSystemProcesses);}else{//已经提升权限则不不需要显示按钮ShowWindow(GetDlgItem(hwnd, IDC_BTN_SYSTEM_PROCESSES), SW_HIDE);//将组合列表框扩展到整个对话框的宽度MoveWindow(GetDlgItem(hwnd, IDC_BTN_SYSTEM_PROCESSES),0,0,0,0,FALSE);}}//隐藏“模块帮助”列表框ShowWindow(GetDlgItem(hwnd, IDC_MODULEHELP), SW_HIDE);//使输出窗口使用等宽字体SetWindowFont(GetDlgItem(hwnd, IDC_RESULTS),GetStockFont(ANSI_FIXED_FONT), FALSE);//默认下,显示运行中的进程Dlg_PopulateProcessList(hwnd);return (TRUE);
}//
BOOL Dlg_OnSize(HWND hwnd, UINT state, int cx, int cy)
{RECT btnRect;HWND hwndCtrl = GetDlgItem(hwnd, IDC_BTN_SYSTEM_PROCESSES);GetClientRect(hwndCtrl, &btnRect);RECT rc;int n = LOWORD(GetDialogBaseUnits());//字体的宽度hwndCtrl = GetDlgItem(hwnd, IDC_PROCESSMODULELIST);GetClientRect(hwndCtrl, &rc);SetWindowPos(hwndCtrl, NULL,n + n + btnRect.right,//按钮宽度+一个字符宽度n,//y=一个字符的高度cx - n - n - n - btnRect.right,//Combox宽度,右边距留一字符宽度rc.bottom,SWP_NOZORDER);hwndCtrl = GetDlgItem(hwnd, IDC_RESULTS);SetWindowPos(hwndCtrl, NULL,n,n + rc.bottom + n,cx - n - n,cy - (n + rc.bottom + n) - n,SWP_NOZORDER);return 0;
}//
void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtrl, UINT codeNotify)
{static BOOL s_fProcesses = TRUE;switch (id){case IDCANCEL:EndDialog(hwnd, id);break;//以管理员身份重启应用程序case IDC_BTN_SYSTEM_PROCESSES:{//case分支里面定义变量,要加大括号ShowWindow(hwnd, SW_HIDE);TCHAR szApplication[MAX_PATH];DWORD cchLength = _countof(szApplication);//获取进程的完整银蛇名称//第二个参为0表示使用win32路径格式,PROCESS_NAME_NATIVE,表示使用本地系统路径格式//第四个参数:返回字符串中字符的个数(不含\0)QueryFullProcessImageName(GetCurrentProcess(), 0, szApplication, &cchLength);DWORD dwStatus = StartElevatedProcess(szApplication, NULL);//手动提升权限if (dwStatus == S_OK){//不需要极限在低特权下工作,退出本进程ExitProcess(0);}//否则,新进程如果启动失败,重新显示本进程的主窗口ShowWindow(hwnd, SW_SHOWNORMAL);}break;//Processes菜单case ID_PROCESSES:s_fProcesses = TRUE;//MF_BYCOMMAND:通过ID定位EnableMenuItem(GetMenu(hwnd), ID_VMMAP, MF_BYCOMMAND | MF_ENABLED);DrawMenuBar(hwnd);Dlg_PopulateProcessList(hwnd);break;//modules菜单项case ID_MODULES:EnableMenuItem(GetMenu(hwnd), ID_VMMAP,MF_BYCOMMAND|MF_GRAYED);DrawMenuBar(hwnd);s_fProcesses = FALSE;Dlg_PopulateModuleList(hwnd);break;case IDC_PROCESSMODULELIST:if (codeNotify == CBN_SELCHANGE){DWORD dw = ComboBox_GetCurSel(hwndCtrl);if (s_fProcesses){dw = (DWORD)ComboBox_GetItemData(hwndCtrl, dw);//process idShowProcessInfo(GetDlgItem(hwnd, IDC_RESULTS), dw);}else{//完整路径的索引在helper listbox中dw = (DWORD)ComboBox_GetItemData(hwndCtrl, dw);TCHAR szModulePath[1024];ListBox_GetText(GetDlgItem(hwnd, IDC_MODULEHELP),dw, szModulePath);ShowModeleInfo(GetDlgItem(hwnd, IDC_RESULTS), szModulePath);}}break;//VMAP菜单0case ID_VMMAP:{TCHAR szCmdLine[32];//下拉列表框HWND hwndCB = GetDlgItem(hwnd, IDC_PROCESSMODULELIST);DWORD dwProcessId = (DWORD)ComboBox_GetItemData(hwndCB, ComboBox_GetCurSel(hwndCB));StringCchPrintf(szCmdLine, _countof(szCmdLine), TEXT("%d"),dwProcessId);DWORD dwStatus =StartElevatedProcess(TEXT("\"14-VMMap.exe\""), szCmdLine);//以管理员身份运行14-VMMap.exe程序时,会进行提升权限的询问,如果时用户拒绝//则显示下列消息框if (dwStatus == ERROR_CANCELLED){chMB("Failed to run 14-VMMap.exe:you refused access.");}}break;}
}//手动提升权限
DWORD StartElevatedProcess(LPCTSTR szExecutable, LPCTSTR szCmdLine)
{//初始化结构体SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };//请求管理员身份sei.lpVerb = TEXT("runas");//run administrator?//传入要提高权限的应用城项名sei.lpFile = szExecutable;//传入命令行参数sei.lpParameters = szCmdLine;//窗口正常显示,否则新启动的进程,七窗口将被隐藏sei.nShow = SW_SHOWNORMAL;ShellExecuteEx(&sei);return (GetLastError());
}//获取令牌提升的类型机判断当前进程是否以管理员身份运行
BOOL GetProcessElevation(TOKEN_ELEVATION_TYPE* pElevationType, BOOL* pIsAdmin)
{HANDLE hToken = NULL;DWORD dwSize;//获取当前进程的Token if (!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken)){return (FALSE);}BOOL bResult = FALSE;//获取提升类型if (GetTokenInformation(hToken,TokenElevationType,pElevationType,sizeof(TOKEN_ELEVATION_TYPE),&dwSize)){//创建管理员组的SIDbyte adminSID[SECURITY_MAX_SID_SIZE];dwSize = sizeof(adminSID);CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, &adminSID,&dwSize);//筛选令牌if (*pElevationType == TokenElevationTypeLimited){//取地与筛选令牌关联的未筛选令牌HANDLE hUnfilTeredToken = NULL;GetTokenInformation(hToken, TokenLinkedToken, (void*)&hUnfilTeredToken, sizeof(HANDLE), &dwSize);//通过初始未被筛选的令牌判断是否包含管理员SIDif (CheckTokenMembership(hUnfilTeredToken,&adminSID,pIsAdmin)){bResult = TRUE;}//关闭未筛选的令牌CloseHandle(hUnfilTeredToken);}else{//未筛选令牌*pIsAdmin = IsUserAnAdmin();bResult = TRUE;}}//关闭当前进程的令牌CloseHandle(hToken);return (bResult);
}VOID ShowModeleInfo(HWND hwnd, PCTSTR pszModulePath)
{SetWindowText(hwnd, TEXT(" "));//Clear the output box CToolhelp thProcesses(TH32CS_SNAPPROCESS);PROCESSENTRY32 pe = { sizeof(pe) };BOOL fOk = thProcesses.ProcessFirst(&pe);AddText(hwnd, TEXT("Pathname:%s\r\n\r\n"), pszModulePath);AddText(hwnd, TEXT("Process Informaton:\r\n"));AddText(hwnd, TEXT(" PID %-*s Process\r\n"),s_cchAddress, TEXT("BaseAddr"));for (; fOk; fOk = thProcesses.ProcessNext(&pe)){CToolhelp thModules(TH32CS_SNAPMODULE, pe.th32ProcessID);MODULEENTRY32 me = { sizeof(me) };BOOL fOk = thModules.ModuleFirst(&me);for (;fOk;fOk = thModules.ModuleNext(&me)){if (_tcscmp(me.szExePath, pszModulePath) == 0){AddText(hwnd, TEXT(" %08X %p %s\r\n"),pe.th32ProcessID, me.modBaseAddr, pe.szExeFile);}}}
}void AddText(HWND hwnd, PCTSTR pszFormat, ...)
{va_list argList;va_start(argList, pszFormat);TCHAR sz[20 * 1024];Edit_GetText(hwnd, sz, _countof(sz));_vstprintf_s(_tcschr(sz, TEXT('\0')), _countof(sz) - _tcslen(sz),pszFormat, argList);Edit_SetText(hwnd, sz);va_end(argList);
}VOID ShowProcessInfo(HWND hwnd, DWORD dwProcessID) {SetWindowText(hwnd, TEXT("")); // Clear the output boxCToolhelp th(TH32CS_SNAPALL, dwProcessID);// Show Process detailsPROCESSENTRY32 pe = { sizeof(pe) };BOOL fOk = th.ProcessFirst(&pe);for (; fOk; fOk = th.ProcessNext(&pe)) {if (pe.th32ProcessID == dwProcessID) {TCHAR szCmdLine[1024];if (GetProcessCmdLine(dwProcessID, szCmdLine, _countof(szCmdLine))) {AddText(hwnd,TEXT("Command line: %s %s\r\n"), pe.szExeFile, szCmdLine);}else {AddText(hwnd, TEXT("Filename: %s\r\n"), pe.szExeFile);}AddText(hwnd, TEXT(" PID=%08X, ParentPID=%08X, ")TEXT("PriorityClass=%d, Threads=%d, Heaps=%d\r\n"),pe.th32ProcessID, pe.th32ParentProcessID,pe.pcPriClassBase, pe.cntThreads,th.HowManyHeaps());TCHAR szOwner[MAX_PATH + 1];if (GetProcessOwner(dwProcessID, szOwner, MAX_PATH)) {AddText(hwnd, TEXT("Owner: %s\r\n"), szOwner);}break; // No need to continue looping}}// Show Modules in the Process// Number of characters to display an addressAddText(hwnd, TEXT("\r\nModules Information:\r\n")TEXT(" Usage %-*s(%-*s) %10s Module\r\n"),s_cchAddress, TEXT("BaseAddr"),s_cchAddress, TEXT("ImagAddr"), TEXT("Size"));MODULEENTRY32 me = { sizeof(me) };fOk = th.ModuleFirst(&me);for (; fOk; fOk = th.ModuleNext(&me)) {if (me.ProccntUsage == 65535) {// Module was implicitly loaded and cannot be unloadedAddText(hwnd, TEXT(" Fixed"));}else {AddText(hwnd, TEXT(" %5d"), me.ProccntUsage);}// Try to format the size in kb.TCHAR szFormattedSize[64];if (StrFormatKBSize(me.modBaseSize, szFormattedSize,_countof(szFormattedSize)) == NULL){StringCchPrintf(szFormattedSize, _countof(szFormattedSize),TEXT("%10u"), me.modBaseSize);}PVOID pvPreferredBaseAddr =GetModulePreferredBaseAddr(pe.th32ProcessID, me.modBaseAddr);if (me.modBaseAddr == pvPreferredBaseAddr) {AddText(hwnd, TEXT(" %p %*s %10s %s\r\n"),me.modBaseAddr, s_cchAddress, TEXT(""),szFormattedSize, me.szExePath);}else {AddText(hwnd, TEXT(" %p(%p) %10s %s\r\n"),me.modBaseAddr, pvPreferredBaseAddr,szFormattedSize, me.szExePath);}}// Show threads in the processAddText(hwnd, TEXT("\r\nThread Information:\r\n")TEXT(" TID Priority\r\n"));THREADENTRY32 te = { sizeof(te) };fOk = th.ThreadFirst(&te);for (; fOk; fOk = th.ThreadNext(&te)) {if (te.th32OwnerProcessID == dwProcessID) {int nPriority = te.tpBasePri + te.tpDeltaPri;if ((te.tpBasePri < 16) && (nPriority > 15)) nPriority = 15;if ((te.tpBasePri > 15) && (nPriority > 31)) nPriority = 31;if ((te.tpBasePri < 16) && (nPriority < 1)) nPriority = 1;if ((te.tpBasePri > 15) && (nPriority < 16)) nPriority = 16;AddText(hwnd, TEXT(" %08X %2d\r\n"),te.th32ThreadID, nPriority);}}
}BOOL GetProcessCmdLine(HANDLE hProcess, LPTSTR szCmdLine, DWORD Size) {// Sanity checksif ((hProcess == NULL) || (szCmdLine == NULL) || (Size == 0))return(FALSE);// 0. Get the Process Environment Block addressint iReturn = 1;DWORD dwSize;SIZE_T size;PROCESS_BASIC_INFORMATION pbi;// The PEB was supposed to always be at address 0x7ffdf000 in XP...// ... but, here is the "right" way to get it now in Vista.iReturn =_NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), &dwSize);// NtQueryInformationProcess returns a negative value if it failsif (iReturn >= 0) {// 1. Find the Process Environment Block__PEB PEB;size = dwSize;if (!ReadProcessMemory(hProcess, pbi.PebBaseAddress, &PEB,sizeof(PEB), &size)) {// Call GetLastError() if you need to know whyreturn(FALSE);}// 2. From this PEB, get the address of the block containing // a pointer to the CmdLine__INFOBLOCK Block;if (!ReadProcessMemory(hProcess, (LPVOID)PEB.InfoBlockAddress,&Block, sizeof(Block), &size)) {// Call GetLastError() if you need to know whyreturn(FALSE);}// 3. Get the CmdLinewchar_t wszCmdLine[MAX_PATH + 1];if (!ReadProcessMemory(hProcess, (LPVOID)Block.wszCmdLineAddress,wszCmdLine, MAX_PATH * sizeof(wchar_t), &size)) {// Call GetLastError() if you need to know whyreturn(FALSE);}// 4. Skip the application pathname// it can be empty, "c:\...\app.exe" or c:\...\app.exewchar_t* pPos = wszCmdLine;if (*pPos != L'\0') {if (*pPos == L'"') {// Find the next " characterpPos = wcschr(&pPos[1], L'"');}else {// Find the next SPACE characterpPos = wcschr(&pPos[1], L' ');}// Skip itif (pPos != NULL)pPos++;}// Copy it backif (pPos != NULL) {if (*pPos != L'\0') {
#ifdef UNICODE// Both strings are in UNICODE._tcscpy_s(szCmdLine, Size, pPos);
#else// from UNICODE to ANSIMultiByteToWideChar(CP_ACP, 0, szCmdLine, Size,pPos, wcslen(pPos));
#endif}elseszCmdLine[0] = TEXT('\0');}elseszCmdLine[0] = TEXT('\0');}else {return(FALSE);}return(TRUE);
}BOOL GetProcessCmdLine(DWORD PID, LPTSTR szCmdLine, DWORD Size) {// Sanity checksif ((PID <= 0) || (szCmdLine == NULL))return(FALSE);// Check if we can get information for this processHANDLE hProcess =OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, PID);if (hProcess == NULL)return(FALSE);BOOL bReturn = GetProcessCmdLine(hProcess, szCmdLine, Size);// Don't forget to release the process handleCloseHandle(hProcess);return(bReturn);
}VOID FormatSizeInKB(DWORD dwSize, DWORD nCharacters,LPTSTR szSize, size_t cchSize) {TCHAR szFormattedSize[64];if (StrFormatKBSize(dwSize, szFormattedSize,_countof(szFormattedSize)) == NULL) {StringCchPrintf(szFormattedSize, _countof(szFormattedSize), TEXT("%8u"), dwSize);}// Format to the right nCharacter width if needed.if (_tcslen(szFormattedSize) < nCharacters) {DWORD current = 0;for (current = 0;current < (nCharacters - _tcslen(szFormattedSize));current++) {szSize[current] = TEXT(' ');}szSize[current] = TEXT('\0');_tcscat_s(szSize, cchSize - current, szFormattedSize);}
}VOID Dlg_PopulateProcessList(HWND hwnd) {HWND hwndList = GetDlgItem(hwnd, IDC_PROCESSMODULELIST);SetWindowRedraw(hwndList, FALSE);ComboBox_ResetContent(hwndList);CToolhelp thProcesses(TH32CS_SNAPPROCESS);PROCESSENTRY32 pe = { sizeof(pe) };BOOL fOk = thProcesses.ProcessFirst(&pe);for (; fOk; fOk = thProcesses.ProcessNext(&pe)) {TCHAR sz[1024];// Place the process name (without its path) & ID in the listPCTSTR pszExeFile = _tcsrchr(pe.szExeFile, TEXT('\\'));if (pszExeFile == NULL) {pszExeFile = pe.szExeFile;}else {pszExeFile++; // Skip over the slash}// Append the code/resource integrity level and policyDWORD dwCodeIntegrityLevel = 0;DWORD dwCodePolicy = TOKEN_MANDATORY_POLICY_OFF;DWORD dwResourcePolicy = 0;DWORD dwResourceIntegrityLevel = 0;TCHAR szCodeDetails[256];szCodeDetails[0] = TEXT('\0');TCHAR szResourceDetails[256];szResourceDetails[0] = TEXT('\0');if (GetProcessIntegrityLevel(pe.th32ProcessID, &dwCodeIntegrityLevel,&dwCodePolicy, &dwResourceIntegrityLevel, &dwResourcePolicy)) {switch (dwCodeIntegrityLevel) {case SECURITY_MANDATORY_LOW_RID:_tcscpy_s(szCodeDetails, _countof(szCodeDetails),TEXT("- Low "));break;case SECURITY_MANDATORY_MEDIUM_RID:_tcscpy_s(szCodeDetails, _countof(szCodeDetails),TEXT("- Medium "));break;case SECURITY_MANDATORY_HIGH_RID:_tcscpy_s(szCodeDetails, _countof(szCodeDetails),TEXT("- High "));break;case SECURITY_MANDATORY_SYSTEM_RID:_tcscpy_s(szCodeDetails, _countof(szCodeDetails),TEXT("- System "));break;default:_tcscpy_s(szCodeDetails, _countof(szCodeDetails),TEXT("- ??? "));}if (dwCodePolicy == TOKEN_MANDATORY_POLICY_OFF) { // = 0_tcscat_s(szCodeDetails,_countof(szCodeDetails), TEXT(" + no policy"));}else {if ((dwCodePolicy & TOKEN_MANDATORY_POLICY_VALID_MASK) == 0) {_tcscat_s(szCodeDetails, _countof(szCodeDetails),TEXT(" + ???"));}else {if ((dwCodePolicy & TOKEN_MANDATORY_POLICY_NO_WRITE_UP)== TOKEN_MANDATORY_POLICY_NO_WRITE_UP) {_tcscat_s(szCodeDetails, _countof(szCodeDetails),TEXT(" + no write-up"));}if ((dwCodePolicy & TOKEN_MANDATORY_POLICY_NEW_PROCESS_MIN)== TOKEN_MANDATORY_POLICY_NEW_PROCESS_MIN) {_tcscat_s(szCodeDetails, _countof(szCodeDetails),TEXT(" + new process min"));}}}switch (dwResourceIntegrityLevel) {case SECURITY_MANDATORY_LOW_RID:_tcscpy_s(szResourceDetails,_countof(szResourceDetails), TEXT("Low"));break;case SECURITY_MANDATORY_MEDIUM_RID:_tcscpy_s(szResourceDetails,_countof(szResourceDetails), TEXT("Medium"));break;case SECURITY_MANDATORY_HIGH_RID:_tcscpy_s(szResourceDetails,_countof(szResourceDetails), TEXT("High"));break;case SECURITY_MANDATORY_SYSTEM_RID:_tcscpy_s(szResourceDetails,_countof(szResourceDetails), TEXT("System"));break;case 0:_tcscpy_s(szResourceDetails,_countof(szResourceDetails), TEXT("Not set"));break;default:_tcscpy_s(szResourceDetails,_countof(szResourceDetails), TEXT("???"));}if (dwResourcePolicy == 0) { // = 0_tcscat_s(szResourceDetails,_countof(szResourceDetails), TEXT(" + 0 policy"));}else {if ((dwResourcePolicy & TOKEN_MANDATORY_POLICY_VALID_MASK) == 0) {_tcscat_s(szResourceDetails,_countof(szResourceDetails), TEXT(" + ???"));}else {if ((dwResourcePolicy & SYSTEM_MANDATORY_LABEL_NO_WRITE_UP)== SYSTEM_MANDATORY_LABEL_NO_WRITE_UP) {_tcscat_s(szResourceDetails,_countof(szResourceDetails),TEXT(" + no write-up"));}if ((dwResourcePolicy & SYSTEM_MANDATORY_LABEL_NO_READ_UP)== SYSTEM_MANDATORY_LABEL_NO_READ_UP) {_tcscat_s(szResourceDetails,_countof(szResourceDetails),TEXT(" + no read-up"));}if ((dwResourcePolicy & SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP)== SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP) {_tcscat_s(szResourceDetails,_countof(szResourceDetails),TEXT(" + no execute-up"));}}}}StringCchPrintf(sz, _countof(sz), TEXT("%s (0x%08X) %s [%s]"),pszExeFile, pe.th32ProcessID, szCodeDetails, szResourceDetails);int n = ComboBox_AddString(hwndList, sz);// Associate the process ID with the added itemComboBox_SetItemData(hwndList, n, pe.th32ProcessID);}ComboBox_SetCurSel(hwndList, 0); // Select the first entry// Simulate the user selecting this first item so that the// results pane shows something interestingFORWARD_WM_COMMAND(hwnd, IDC_PROCESSMODULELIST,hwndList, CBN_SELCHANGE, SendMessage);SetWindowRedraw(hwndList, TRUE);InvalidateRect(hwndList, NULL, FALSE);
}///VOID Dlg_PopulateModuleList(HWND hwnd) {HWND hwndModuleHelp = GetDlgItem(hwnd, IDC_MODULEHELP);ListBox_ResetContent(hwndModuleHelp);CToolhelp thProcesses(TH32CS_SNAPPROCESS);PROCESSENTRY32 pe = { sizeof(pe) };BOOL fOk = thProcesses.ProcessFirst(&pe);for (; fOk; fOk = thProcesses.ProcessNext(&pe)) {CToolhelp thModules(TH32CS_SNAPMODULE, pe.th32ProcessID);MODULEENTRY32 me = { sizeof(me) };BOOL fOk = thModules.ModuleFirst(&me);for (; fOk; fOk = thModules.ModuleNext(&me)) {int n = ListBox_FindStringExact(hwndModuleHelp, -1, me.szExePath);if (n == LB_ERR) {// This module hasn't been added beforeListBox_AddString(hwndModuleHelp, me.szExePath);}}}HWND hwndList = GetDlgItem(hwnd, IDC_PROCESSMODULELIST);SetWindowRedraw(hwndList, FALSE);ComboBox_ResetContent(hwndList);int nNumModules = ListBox_GetCount(hwndModuleHelp);for (int i = 0; i < nNumModules; i++) {TCHAR sz[1024];ListBox_GetText(hwndModuleHelp, i, sz);// Place module name (without its path) in the listint nIndex = ComboBox_AddString(hwndList, _tcsrchr(sz, TEXT('\\')) + 1);// Associate the index of the full path with the added itemComboBox_SetItemData(hwndList, nIndex, i);}ComboBox_SetCurSel(hwndList, 0); // Select the first entry// Simulate the user selecting this first item so that the// results pane shows something interestingFORWARD_WM_COMMAND(hwnd, IDC_PROCESSMODULELIST,hwndList, CBN_SELCHANGE, SendMessage);SetWindowRedraw(hwndList, TRUE);InvalidateRect(hwndList, NULL, FALSE);
}BOOL GetProcessIntegrityLevel(HANDLE hProcess, PDWORD pIntegrityLevel,PDWORD pPolicy, PDWORD pResourceIntegrityLevel, PDWORD pResourcePolicy) {HANDLE hToken = NULL;if (!OpenProcessToken(hProcess, TOKEN_READ, &hToken)) {return(FALSE);}BOOL bReturn = FALSE;// First, compute the size of the buffer to get the Integrity levelDWORD dwNeededSize = 0;if (!GetTokenInformation(hToken, TokenIntegrityLevel, NULL, 0, &dwNeededSize)) {PTOKEN_MANDATORY_LABEL pTokenInfo = NULL;if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {// Second, allocate a memory block with the the required size pTokenInfo = (PTOKEN_MANDATORY_LABEL)LocalAlloc(0, dwNeededSize);if (pTokenInfo != NULL) {// And finally, ask for the integrity levelif (GetTokenInformation(hToken, TokenIntegrityLevel, pTokenInfo,dwNeededSize, &dwNeededSize)) {*pIntegrityLevel =*GetSidSubAuthority(pTokenInfo->Label.Sid,(*GetSidSubAuthorityCount(pTokenInfo->Label.Sid) - 1));bReturn = TRUE;}// Don't forget to free the memoryLocalFree(pTokenInfo);}}}// Try to get the policy if the integrity level was availableif (bReturn) {*pPolicy = TOKEN_MANDATORY_POLICY_OFF;dwNeededSize = sizeof(DWORD);GetTokenInformation(hToken, TokenMandatoryPolicy, pPolicy,dwNeededSize, &dwNeededSize);}// Look for the resource policy*pResourceIntegrityLevel = 0; // 0 means none explicitely set*pResourcePolicy = 0;PACL pSACL = NULL;PSECURITY_DESCRIPTOR pSD = NULL;DWORD dwResult = ERROR_SUCCESS;// Look for the no-read-up/no-write-up policy in the SACLif (hToken != NULL) {dwResult =GetSecurityInfo(hProcess, SE_KERNEL_OBJECT,LABEL_SECURITY_INFORMATION,NULL, NULL, NULL,&pSACL, &pSD);if (dwResult == ERROR_SUCCESS) {if (pSACL != NULL) {SYSTEM_MANDATORY_LABEL_ACE* pACE = NULL;if ((pSACL->AceCount > 0) && (GetAce(pSACL, 0, (PVOID*)&pACE))) {if (pACE != NULL) {SID* pSID = (SID*)(&pACE->SidStart);*pResourceIntegrityLevel = pSID->SubAuthority[0];*pResourcePolicy = pACE->Mask;}}}}// Cleanup memory allocated on our behalfif (pSD != NULL) LocalFree(pSD);}// Don't forget to close the token handle.CloseHandle(hToken);return(bReturn);
}BOOL GetProcessIntegrityLevel(DWORD PID, PDWORD pIntegrityLevel,PDWORD pPolicy, PDWORD pResourceIntegrityLevel, PDWORD pResourcePolicy) {// Sanity checksif ((PID <= 0) || (pIntegrityLevel == NULL))return(FALSE);// Check if we can get information for this processHANDLE hProcess = OpenProcess(READ_CONTROL | PROCESS_QUERY_INFORMATION,FALSE, PID);if (hProcess == NULL)return(FALSE);BOOL bReturn = GetProcessIntegrityLevel(hProcess, pIntegrityLevel,pPolicy, pResourceIntegrityLevel, pResourcePolicy);// Don't forget to release the process handleCloseHandle(hProcess);return(bReturn);
}PVOID GetModulePreferredBaseAddr(DWORD dwProcessId, PVOID pvModuleRemote) {PVOID pvModulePreferredBaseAddr = NULL;IMAGE_DOS_HEADER idh;IMAGE_NT_HEADERS inth;// Read the remote module's DOS headerToolhelp32ReadProcessMemory(dwProcessId,pvModuleRemote, &idh, sizeof(idh), NULL);// Verify the DOS image headerif (idh.e_magic == IMAGE_DOS_SIGNATURE) {// Read the remote module's NT headerToolhelp32ReadProcessMemory(dwProcessId,(PBYTE)pvModuleRemote + idh.e_lfanew, &inth, sizeof(inth), NULL);// Verify the NT image headerif (inth.Signature == IMAGE_NT_SIGNATURE) {// This is valid NT header, get the image's preferred base addresspvModulePreferredBaseAddr = (PVOID)inth.OptionalHeader.ImageBase;}}return(pvModulePreferredBaseAddr);
}
相关文章:
windows 显示进程地址空间
windows 显示进程地址空间 windows 显示进程地址空间 文章目录 windows 显示进程地址空间显示进程地址空间 显示进程地址空间 /* 3-ProcessInfo.cpp 显示进程地址空间 */#include "..\\CommonFiles\\CmnHdr.h" #include "..\\CommonFiles\\Toolhelp.h"#i…...

Android 12 SystemUI下拉状态栏禁止QuickQSPanel展开
1.概述 遇到需求,QuickQSPanel首次下拉后展示快捷功能模块以后就是显示QuickQSPanel,而不展开QSPanel,接下来要从下滑手势下拉出状态栏分析功能实现。也就是直接是展开状态。 2、涉及核心类 frameworks\base\packages\SystemUI\src\com\and…...

二分思想与相关问题(下)
接下来详细讲解几道比较难的例题,仔细体会二分和其他概念混合在一起的趣味。 下面这道题涉及了“碎片拼接”的概念,很妙,也很难想。 P r o b l e m 5 Problem5 Problem5 同时运行N台电脑的最长时间 LeetCode2141 你有 n 台电脑。给你整数 n…...

【算法专题】搜索算法
二叉树剪枝 LCR 047. 二叉树剪枝 - 力扣(LeetCode) 本题要求我们将全部为0的二叉树去掉,也就是剪枝,当我们举一个具体的例子进行模拟时,会发现,只关注于对其中一个子树的根节点进行剪枝,由于我…...
B2064 斐波那契数列
题目描述 斐波那契数列是指这样的数列:数列的第一个和第二个数都为 11,接下来每个数都等于前面 22 个数之和。 给出一个正整数 aa,要求斐波那契数列中第 aa 个数是多少。 输入格式 第 11 行是测试数据的组数 nn,后面跟着 nn 行…...

Spark的介绍
一、分布式的思想 不管是数据也好,计算也好,都没有最大的电脑,而是多个小电脑组合而成。 存储:将3T的文件拆分成若干个小文件,例如每500M一个小文件,将这些小文件存储在不同的机器上 。 -- HDFS 计算&#…...
SpringBoot项目是如何启动
启动步骤 概念 运行main方法,初始化SpringApplication 从spring.factories读取listener ApplicationContentInitializer运行run方法读取环境变量,配置信息创建SpringApplication上下文预初始化上下文,将启动类作为配置类进行读取调用 refres…...

科技之光,照亮未来之路“2024南京国际人工智能展会”
全球科技产业的版图正以前所未有的速度重构,而位于中国东部沿海经济带的江浙沪地区,作为科技创新与产业升级的高地,始终站在这一浪潮的最前沿。2024年,这一区域的科技盛宴——“2024南京人工智能展会”即将在南京国际博览中心盛大…...
在深度学习计算机视觉的语义分割中,Boundary和Edge的区别是?
在深度学习中的计算机视觉任务中,语义分割中的 Boundary 和 Edge 其实有一些相似之处,但它们的定义和使用场景略有不同。下面是两者的区别: 1. Boundary(边界) 定义:Boundary 是指一个对象或区域的边界&a…...

【JAVA入门】Day41 - 字节缓冲流和字符缓冲流
【JAVA入门】Day41 - 字节缓冲流和字符缓冲流 文章目录 【JAVA入门】Day41 - 字节缓冲流和字符缓冲流一、缓冲流的体系结构二、字节缓冲流2.1 字节缓冲流提高效率的底层原理 三、字符缓冲流 在IO流体系中,FileInputStream,FileOutputStream,F…...
collocate join,bucket join,broadcast join,shuffle join对比分析
在分布式计算和大数据处理中,尤其是在使用像 Apache Spark、Hive 等大数据处理框架时,Join 操作是非常常见的。根据数据分布方式和执行机制,Join 操作可以分为不同的类型,如 Collocate Join、Bucket Join、Broadcast Join 和 Shuffle Join。以下是它们的详细对比分析: 1.…...

微信自动通过好友和自动拉人进群,微加机器人这个功能太好用了
又发现一个好用的功能,之前就想找一个这种工具,现在发现可以利用微加机器人的两个功能来实现,分别是加好友和关键词拉群 首先 微加机器人的专业版 > 功能 > 加好友设置 可以设置一个关键词通过,这样别人加好友的时候只需要输入制定内…...

R语言统计分析——功效分析3(相关、线性模型)
参考资料:R语言实战【第2版】 1、相关性 pwr.r.test()函数可以对相关性分析进行功效分析。格式如下: pwr.r.test(n, r, sig.level, power, alternative) 其中,n是观测数目,r是效应值(通过线性相关系数衡量࿰…...

Django创建模型
1、根据创建好应用模块 python manage.py startapp tests 2、在models文件里创建模型 from django.db import modelsfrom book.models import User# Create your models here. class Tests(models.Model):STATUS_CHOICES ((0, 启用),(1, 停用),# 更多状态...)add_time mode…...

盘点2024年大家都在用的短视频剪辑工具
你现在休息的时间是不是都靠短视频来消遣?看着看着你就会发现短视频制作好像我也可以了吧?这次我就介绍一些简单好操作的短视频剪辑工具。 1.FOXIT视频剪辑 连接直达>>https://www.pdf365.cn/foxitclip/ 短视频剪辑其实也不难,只需…...

“左侧文字横向”的QTabWidget
左侧用 QToolButton 组, 右侧用 QStackedWidget,信号槽绑定切换页面 可定制化高 QButtonGroup* btnGp new QButtonGroup(this);btnGp->addButton(ui->btn1, 0);btnGp->addButton(ui->btn2, 1);btnGp->addButton(ui->btn3, 2);connect…...
python学习之字符串操作
str python # 定义一个字符串变量 print(id(str))print(str) # 打印整个字符串 print(str[0:-1]) # 打印字符串第一个到倒数第二个字符(不包含倒数第一个字符) print(str[0]) # 打印字符串的第一个字符 print(str[2:5]) # 打印字符串第三到第…...

第7篇:【系统分析师】计算机网络
考点汇总 考点详情 1网络模型和协议:OSI/RM七层模型,网络标准和协议,TCP/IP协议族,端口 七层:应用层,表示层,会话层,传输层,网络层,数据链路层,…...

无人机培训机构组装调试技术详解
一、基础知识学习 在进入无人机组装调试领域之前,扎实的基础知识是不可或缺的。学员需掌握以下内容: 1. 无人机基本原理:了解无人机的飞行原理,包括升力、推力、重力和阻力等基本物理概念,以及无人机的飞行控制系统&…...

汽车的舒适进入功能是什么意思?
移动管家汽车的舒适进入系统是指无钥匙进入功能,它允许驾驶者在距离车辆一定范围内自动感应解锁车辆,并具备无钥匙启动功能。舒适进入系统的核心优势包括: 智能化操作:无需传统钥匙,通过智能感应实现车门解锁和…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...

深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...

什么是VR全景技术
VR全景技术,全称为虚拟现实全景技术,是通过计算机图像模拟生成三维空间中的虚拟世界,使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验,结合图文、3D、音视频等多媒体元素…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...