在很多情况下,为了测试代码或扩展操作系统的功能,软件开发人员或测试人员必须截取系统函数调用。有一些软件包能够提供该功能,如微软公司的 Detours* 库,或 OK Thinking Software 的 Syringe*。但是从另一个角度而言,开发人员可能希望不需借助第三方软件,自己就能实现该功能。 本文描述了函数截取的几种不同方式,并详细介绍了无需使用商业软件包,也不需受 GNU*(通用公共许可证)许可的约束,就能够实现该功能的一种通用方法。本文所有材料由英特尔公司开发,或根据 MSDN* 样本代码修改而来。截取系统函数调用的两项基本技术大部分截取任意函数调用的方法都是准备一个 DLL,用来替代将被截取的目标函数,然后将 DLL 注入至目标进程;在与目标进程连接的基础上, DLL 将自己与目标函数相连。这种技术之所以适合此任务,是因为在大多数情况下我们无法获得目标应用程序的源代码,而这种技术只需相对简单地编写一个包含代换函数的 DLL,就可将其与软件的其它部分分离开来。 两种截取方法已经过研究和分析。Syringe 通过修改函数输入条目( thunking 表)运行。而Detours 库则直接修改目标函数( 在目标进程空间内),并无条件地跳转至代换函数。此外,它还提供能够调用原始函数的 trampoline 函数。 Detours 技术之所以采用后一种方法,是因为在许多情况下,Syringe 无法找到 thunk,并且它不能提供 trampoline功能来调用原始函数。在这两种方法下,注入 DLL 的工作方式相同。 截取系统函数调用的全部工作流程如下所示:
DLL 注入 — 首先,主软件打开目标进程,并使其加载包含代换函数的 DLL。 目标函数修改 — 当 DLL 连接至进程时,它在目标进程空间内修改目标函数,从而直接跳转至 DLL 中的代换函数。Trampoline 函数能够随意调用原始函数。 目标函数截取 — 当调用目标函数时,它直接跳转至 DLL 中的代换函数。如果开发人员希望调用原始的功能,则他或她就可以调用 trampoline 函数。 DLL 注入本节内容完全以 MSDN 文章“ 定制调试诊断工具和实用程序 — 摆脱 DLL“地狱”(DLL Hell)*”为基础,该文章还包括可下载的源代码。在本文附录中可获得 Inject.cpp 和 Inject.h 。已对它们进行了定制以便于集成——仅需将其包括在项目中然后调用 InjectLib 即可。使目标进程加载 DLL 的算法按如下步骤工作:
Inject.cpp 融合了包括稳固的安全特性等大量其它功能,但上述步骤已足够阐明其核心概念。
通过调用 OpenProcess 打开目标进程。 通过调用 VirtualAllocEx 在目标进程中分配内存。利用 WriteProcessMemory 将要被注入的 DLL 名称写入分配的内存。 通过调用 GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW") 来获取 LoadLibrary 的地址; 调用 CreateRemoteThread,指定 LoadLibrary 的入口点,并将 DLL (第 2 步中) 的名称作为其自变量。目标进程将加载 DLL。 利用 VirtualFreeEx 释放分配的内存。已不再需要该内存。 目标函数修改目标函数修改为自我修改代码,尽管在将 jmp 注入进程内存的过程中存在一些缺陷,但它在 MSDN*上具有完善的文件证明。为避免混淆,本节列出了几乎全部的样本代码。 目标函数修改的两个主要方面为代换函数和 trampoline 函数。下面的代码片断为截取 GetSystemPowerStatus API 的 DLL 示例:
这段代码为连接所做的第一件事就是调用 InterceptAPI。需要使用包含目标函数的模块名称、目标函数的名称以及代换函数的地址。 GetSystemPowerStatus 位于 kernel32.dll 中。其它基本的 Win32* API,如 MessageBox 和 PeekMessage,都能够在 user32.dll 中获得。MSDN 指定每个 API 所属的模块;未来的增强版中,将自动为给定的 API 找到正确的模块。 InterceptAPI 将目标函数的前五个字节覆盖为无条件跳转( opcode 0xE9),后面为四个字节的带符号整数(向代换函数的位移)。位移从下一个指令开始;因此需要使用 pbReplaced - (pbTargetCode +4)。进行该代码操作时,需要注意以下两点:现在,当调用 GetSystemPowerStatus 函数时,它跳转至代换函数,然后直接返回调用方,成功截取调用。
将区域覆盖的保护模式改为 VirtualProtect。否则,将发生非法访问错误。 必须使用 FlushInstructionCache 来支持指令已存在于高速缓存中的情况。否则,即使内存中的指令已经有所变化,旧代码仍将在高速缓存中运行。 Trampoline 函数在很多情况下,代换函数除使用自身代码外,还需调用原始目标函数,这样就能够扩展 API 的功能,而不是替换整个 API。Trampoline 函数可以提供该功能。Trampoline 函数的原理如下所示:可能存在一种复杂的情况,即原始代码的第六个字节可能是先前指令的一部分。在这种情况下,函数会覆盖部分先前指令,然后崩溃。在 GetSystemPowerStatus 的情况中,前五个字节后的新指令开始于第七个字节。因此,对于这种工作机制,需要将六个字节复制到 trampoline,并且代码必须相应地调整这个偏移量。 代码需要复制的字节数取决于 API。查看原始目标代码( 利用调试器或反汇编器)并计算需要复制的字节数是非常必要的。未来的增强版将自动检测正确的偏移量。假设我们已经知道正确的偏移量,下面的代码则显示出可建立 trampoline 函数的可扩展 InterceptAPI 函数:
编写一个具有相同声明的哑元函数(dummy function),将作为 trampoline 使用。确保哑元函数的长度超过 10 个字节。 在覆盖目标函数的前五个字节之前,将它们复制到 trampoline 函数的起始处。 利用无条件跳转,将trampoline的第六个字节覆盖为目标函数的第六个字节。 与之前一样覆盖目标函数。 当从代换函数或其它地方调用 trampoline 函数时,它执行复制出的原始代码的前五个字节,然后跳转至实际原始代码的第六个字节。控制返回至 trampoline 的调用方。当完成其它任务时,控制返回至 API 的控制方。 1 BOOL InterceptAPI(HMODULE hLocalModule, const char * c_szDllName, const char * c_szApiName, 2 DWORD dwReplaced, DWORD dwTrampoline, int offset) 3 { 4 int i; 5 DWORD dwOldProtect; 6 DWORD dwAddressToIntercept = (DWORD)GetProcAddress( 7 GetModuleHandle(( char * )c_szDllName), ( char * )c_szApiName); 8 9 BYTE * pbTargetCode = (BYTE * ) dwAddressToIntercept; 10 BYTE * pbReplaced = (BYTE * ) dwReplaced; 11 BYTE * pbTrampoline = (BYTE * ) dwTrampoline; 12 13 // Change the protection of the trampoline region 14 // so that we can overwrite the first 5 + offset bytes. 15 VirtualProtect(( void * ) dwTrampoline, 5 + offset, PAGE_WRITECOPY, & dwOldProtect); 16 for (i = 0 ;i < offset;i ++ ) 17 * pbTrampoline ++ = * pbTargetCode ++ ; 18 pbTargetCode = (BYTE * ) dwAddressToIntercept; 19 20 // Insert unconditional jump in the trampoline. 21 * pbTrampoline ++ = 0xE9 ; // jump rel32 22 * ((signed int * )(pbTrampoline)) = (pbTargetCode + offset) - (pbTrampoline + 4 ); 23 VirtualProtect(( void * ) dwTrampoline, 5 + offset, PAGE_EXECUTE, & dwOldProtect); 24 25 // Overwrite the first 5 bytes of the target function 26 VirtualProtect(( void * ) dwAddressToIntercept, 5 , PAGE_WRITECOPY, & dwOldProtect); 27 * pbTargetCode ++ = 0xE9 ; // jump rel32 28 * ((signed int * )(pbTargetCode)) = pbReplaced - (pbTargetCode + 4 ); 29 VirtualProtect(( void * ) dwAddressToIntercept, 5 , PAGE_EXECUTE, & dwOldProtect); 30 31 // Flush the instruction cache to make sure 32 // the modified code is executed. 33 FlushInstructionCache(GetCurrentProcess(), NULL, NULL); 34 return TRUE; 35 } 36结论本文描述了截取系统函数调用的一种通用方法,同时还提供了 trampoline 函数,从而保留了原始功能。本文仅对方法进行简要描述,并未对完整的软件包作出说明,因此如下一些细节并没有实现:然而,对于开发人员而言,无需依赖第三方软件包,执行截取任意系统函数调用的软件,本文中涉及的技术、说明及源代码已经足够。
自动检测包含目标 API 的模块。 自动检测 trampoline 函数的偏移量。 删除代换函数,并注入 DLL。(到目前为止,清空代换函数的唯一方法是关闭应用程序。) 1 #include " stdafx.h " 2 #include " Inject.h " 3 4 #include < tchar.h > 5 #include < malloc.h > // For alloca 6 #include < pi.h > 7 8 #ifdef UNICODE 9 #define InjectLib InjectLibW 10 #else 11 #define InjectLib InjectLibA 12 #endif // !UNICODE 13 14 BOOL AdjustDacl(HANDLE h, DWORD DesiredAccess) 15 { 16 // the WORLD Sid is trivial to form programmatically (S-1-1-0) 17 SID world = { SID_REVISION, 1 , SECURITY_WORLD_SID_AUTHORITY, 0 }; 18 19 EXPLICIT_ACCESS ea = 20 { 21 DesiredAccess, 22 SET_ACCESS, 23 NO_INHERITANCE, 24 { 25 0 , NO_MULTIPLE_TRUSTEE, 26 TRUSTEE_IS_SID, 27 TRUSTEE_IS_USER, 28 reinterpret_cast < LPTSTR > ( & world) 29 } 30 }; 31 ACL * pdacl = 0 ; 32 DWORD err = SetEntriesInAcl( 1 , & ea, 0 , & pdacl); 33 if (err == ERROR_SUCCESS) 34 { 35 err = SetSecurityInfo(h, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0 , 0 , pdacl, 0 ); 36 LocalFree(pdacl); 37 return (err == ERROR_SUCCESS); 38 } 39 else 40 return (FALSE); 41 } 42 43 // Useful helper function for enabling a single privilege 44 BOOL EnableTokenPrivilege(HANDLE htok, LPCTSTR szPrivilege, TOKEN_PRIVILEGES & tpOld) 45 { 46 TOKEN_PRIVILEGES tp; 47 tp.PrivilegeCount = 1 ; 48 tp.Privileges[ 0 ].Attributes = SE_PRIVILEGE_ENABLED; 49 if (LookupPrivilegeValue( 0 , szPrivilege, & tp.Privileges[ 0 ].Luid)) 50 { 51 // htok must have been opened with the following permissions: 52 // TOKEN_QUERY (to get the old priv setting) 53 // TOKEN_ADJUST_PRIVILEGES (to adjust the priv) 54 DWORD cbOld = sizeof tpOld; 55 if (AdjustTokenPrivileges(htok, FALSE, & tp, cbOld, & tpOld, & cbOld)) 56 // Note that AdjustTokenPrivileges may succeed, and yet 57 // some privileges weren't actually adjusted. 58 // You've got to check GetLastError() to be sure! 59 return (ERROR_NOT_ALL_ASSIGNED != GetLastError()); 60 else 61 return (FALSE); 62 } 63 else 64 return (FALSE); 65 } 66 67 68 // Corresponding restoration helper function 69 BOOL RestoreTokenPrivilege(HANDLE htok, const TOKEN_PRIVILEGES & tpOld) 70 { 71 return (AdjustTokenPrivileges(htok, FALSE, const_cast < TOKEN_PRIVILEGES *> ( & tpOld), 0 , 0 , 0 )); 72 } 73 74 HANDLE GetProcessHandleWithEnoughRights(DWORD PID, DWORD AccessRights) 75 { 76 HANDLE hProcess = ::OpenProcess(AccessRights, FALSE, PID); 77 if (hProcess == NULL) 78 { 79 HANDLE hpWriteDAC = OpenProcess(WRITE_DAC, FALSE, PID); 80 if (hpWriteDAC == NULL) 81 { 82 // hmm, we don't have permissions to modify the DACL83 // time to take ownership
84 HANDLE htok; 85 if ( ! OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, & htok)) 86 return (FALSE); 87 88 TOKEN_PRIVILEGES tpOld; 89 if (EnableTokenPrivilege(htok, SE_TAKE_OWNERSHIP_NAME, tpOld)) 90 { 91 // SeTakeOwnershipPrivilege allows us to open objects with 92 // WRITE_OWNER, but that's about it, so we'll update the owner, 93 // and dup the handle so we can get WRITE_DAC permissions. 94 HANDLE hpWriteOwner = OpenProcess(WRITE_OWNER, FALSE, PID); 95 if (hpWriteOwner != NULL) 96 { 97 BYTE buf[ 512 ]; // this should always be big enough 98 DWORD cb = sizeof buf; 99 if (GetTokenInformation(htok, TokenUser, buf, cb, & cb)) 100 { 101 DWORD err = 102 SetSecurityInfo( 103 hpWriteOwner, 104 SE_KERNEL_OBJECT, 105 OWNER_SECURITY_INFORMATION, 106 reinterpret_cast < TOKEN_USER *> (buf) -> User.Sid, 107 0 , 0 , 0 108 ); 109 if (err == ERROR_SUCCESS) 110 { 111 // now that we're the owner, we've implicitly got WRITE_DAC 112 // permissions, so ask the system to reevaluate our request, 113 // giving us a handle with WRITE_DAC permissions 114 if ( 115 ! DuplicateHandle( 116 GetCurrentProcess(), 117 hpWriteOwner, 118 GetCurrentProcess(), 119 & hpWriteDAC, 120 WRITE_DAC, FALSE, 0 121 ) 122 ) 123 hpWriteDAC = NULL; 124 } 125 } 126 127 // don't forget to close handle 128 ::CloseHandle(hpWriteOwner); 129 } 130 131 // not truly necessary in this app, 132 // but included for completeness 133 RestoreTokenPrivilege(htok, tpOld); 134 } 135 136 // don't forget to close the token handle 137 ::CloseHandle(htok); 138 } 139 140 if (hpWriteDAC) 141 { 142 // we've now got a handle that allows us WRITE_DAC permission 143 AdjustDacl(hpWriteDAC, AccessRights); 144 145 // now that we've granted ourselves permission to access 146 // the process, ask the system to reevaluate our request, 147 // giving us a handle with right permissions 148 if ( 149 ! DuplicateHandle( 150 GetCurrentProcess(), 151 hpWriteDAC, 152 GetCurrentProcess(), 153 & hProcess, 154 AccessRights, 155 FALSE, 156 0 157 ) 158 ) 159 hProcess = NULL; 160 161 CloseHandle(hpWriteDAC); 162 } 163 } 164 165 return (hProcess); 166 } 167 168 BOOL WINAPI InjectLibW(DWORD dwProcessId, PCWSTR pszLibFile) 169 { 170 BOOL fOk = FALSE; // Assume that the function fails 171 HANDLE hProcess = NULL, hThread = NULL; 172 PWSTR pszLibFileRemote = NULL; 173 174 // Get a handle for the target process. 175 hProcess = 176 GetProcessHandleWithEnoughRights( 177 dwProcessId, 178 PROCESS_QUERY_INFORMATION | // Required by Alpha 179 PROCESS_CREATE_THREAD | // For CreateRemoteThread 180 PROCESS_VM_OPERATION | // For VirtualAllocEx/VirtualFreeEx 181 PROCESS_VM_WRITE // For WriteProcessMemory 182 ); 183 if (hProcess == NULL) 184 return (FALSE); 185 186 // Calculate the number of bytes needed for the DLL's pathname 187 int cch = 1 + lstrlenW(pszLibFile); 188 int cb = cch * sizeof (WCHAR); 189 190 // Allocate space in the remote process for the pathname 191 pszLibFileRemote = 192 (PWSTR) VirtualAllocEx(hProcess, NULL, cb, MEM_COMMIT, PAGE_READWRITE); 193 194 if (pszLibFileRemote != NULL) 195 { 196 // Copy the DLL's pathname to the remote process's address space 197 if (WriteProcessMemory(hProcess, pszLibFileRemote, 198 (PVOID) pszLibFile, cb, NULL)) 199 { 200 // Get the real address of LoadLibraryW in Kernel32.dll 201 PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE) 202 GetProcAddress(GetModuleHandle(TEXT( " Kernel32 " )), " LoadLibraryW " ); 203 if (pfnThreadRtn != NULL) 204 { 205 // Create a remote thread that calls LoadLibraryW(DLLPathname) 206 hThread = CreateRemoteThread(hProcess, NULL, 0 , 207 pfnThreadRtn, pszLibFileRemote, 0 , NULL); 208 if (hThread != NULL) 209 { 210 // Wait for the remote thread to terminate 211 WaitForSingleObject(hThread, INFINITE); 212 213 fOk = TRUE; // Everything executed successfully 214 215 CloseHandle(hThread); 216 } 217 } 218 } 219 // Free the remote memory that contained the DLL's pathname 220 VirtualFreeEx(hProcess, pszLibFileRemote, 0 , MEM_RELEASE); 221 } 222 223 CloseHandle(hProcess); 224 225 return (fOk); 226 } 227 228 229 BOOL WINAPI InjectLibA(DWORD dwProcessId, PCSTR pszLibFile) { 230 231 // Allocate a (stack) buffer for the Unicode version of the pathname 232 PWSTR pszLibFileW = (PWSTR) 233 _alloca((lstrlenA(pszLibFile) + 1 ) * sizeof (WCHAR)); 234 235 // Convert the ANSI pathname to its Unicode equivalent 236 wsprintfW(pszLibFileW, L " %S " , pszLibFile); 237 238 // Call the Unicode version of the function to actually do the work. 239 return (InjectLibW(dwProcessId, pszLibFileW)); 240 }
相关推荐
HOOK api 实现封包截取.zip
HOOK api 实现封包截取
想在你的程序中截住API函数吗?那就快看吧!
在你的程序中做一个函数func(...) 调用 func1 = ApiSpy(NULL,"GDI32.DLL","TextOutA",(PROC)func)那么你的程序没次调用TextOut时,就会调用func 为了不破坏原有功能请在func中调用func1。如果想截获整个系统的api,你需要做一个全局HOOK在HOOK的DLL里的初始化时调用本函数。主要代码如下:PROC W
屏幕截取相关API
屏幕截取相关API 适合多个编程语言 里面有讲解屏幕截取需要用到的API,学习好资料
Detours简介 (拦截x86机器上的任意的win32 API函数)
Detours 当然是用detours,微软明显高腾讯一筹,同上,至今没失败过.写这种HOOK一定要再写个测试程序,不要直接HOOK你的目的程序,例如QQ,因为这样不方面更灵活的测试. 说明一下:Detours是微软开发的一个函数库(源代码可在http://research.microsoft.com/sn/detours 免费获得)用于修改运行中的程序在内存中的影像,从而即使没有源代码也能改
RL调参侠之BipedalWalker BipedalWalkerHardcore SAC
前几天用PPO训练了个很一般的agent: RL调参侠之BipedalWalker PPO 我看SpinningUp上面说PPO和SAC是两个领域里各自的State_of_the_art的方法,所以就打算跑SAC试试看,之前因为Open AI Five的原因,一直感觉PPO很牛掰,实际上现在很多自动驾驶的算法也是用PPO在跑,毕竟有一个“必定能够提升期望”的理论保证在这里,我理解这对做项目很大的诱惑。 不过我跑出来的结果明显是SAC更好。 调参侠时间 策略熵的权重alpha用的0.2,我一开始没有看SAC的
Power BI应用案例:淘宝用户行为分析实战
一、案例背景 基于千万级的淘宝用户的使用记录,对淘宝用户的行为进行分析,具体指标包括:日PV、日UV、小时PV、小时UV、不同用户行为的PV、用户购买次数分布、用户购买频次分布、活跃用户消费情况等。通过本案例,可以基本看看Power BI都能分析达到怎么样的效果。 二、数据来源及结构 阿里天池官方发布的1万用户在2014年双十二期间的行为记录,数据量达1200万+。 数据下载地址:...
CreateRemoteThread API 函数心得
昨天晚上找到了个有意思的API CreateRemoteThread(),它可以在别的进程中创建自己需要的线程,我想这个函数在做坏事上肯定很拿手哈~,当然,技术没有好坏,用得好是天使,用得坏是魔鬼,关键在于人。许多API是值得花时间看的,虽然不好懂,但作用强大,因此这里总结一下这个函数的心得,以后若忘了也容易捡起来。 1:我们的目的是这样的:我们启动进程A,让A在进程B中增加一个线程S
Modelsim安装教程以及管理员身份运行patch_dll.bat时找不到文件mgls.dll的解决
Modesim安装教程 Modesim版本有很多,但是安装方式大都相同,我们以modesim.10.5为例,电脑使用的是win10 64位,讲一下安装过程中的步骤以及出现问题的解决方法 一 安装 1.首先解压安装包,在解压的安装包内选择应用程序,右键选择管理员运行。 2.稍等一会,有的电脑会弹出是否允许modesim进行更改,选择 是 即可,然后出现下面的界面,点击下一步。 3.弹出此界面选择安装路径,选择安装路径,我是在D盘新建的文件夹,直接把文件夹中的路径复制在框内。文件夹名称切记不要带中文 4.
以程序的方式操纵NTFS的文件权限
以程序的方式操纵NTFS的文件权限 发表日期:2004-01-29 作者:陈皓[] 出处: Windows NT/2K/XP版本的操作系统都支持NTFS格式的文件系统,这是一个有安全性质的文件系统,你可以通过Windows的资源管理器来设置对每个目录和文件的用户访问权限。这里我就不对NTFS的安全性进行讲述了,我默认你对NTFS的文件目
从CPU视角看PCIe:深入理解x86/ARM平台上BAR、MMIO和PIO的地址翻译与访问机制
本文深入探讨了CPU如何通过BAR、MMIO和PIO机制访问PCIe设备的配置空间,详细解析了x86和ARM平台在地址翻译与访问路径上的差异。重点分析了PCIe配置空间中BAR寄存器的作用与探测机制,以及操作系统如何管理PCIe资源,为开发者提供了性能优化与调试的实用技巧。
postman响应体:“msg“: “请求缺失签名Sign“、 “msg“: “请求缺失时间戳“
请求标头有Sign、Timestamp,但是直接将网址复制到postman时,Headers没有自动生成这两个参数,所以运行时会报错。
用户态隐藏进程的通用版本
一般基于HOOK ZwQuerySystemInformation的隐藏进程都是在驱动模式下进行的, 在这里通过操作内存实现了. 而且达到了不同系统版本的通用性. 厉害...来自驱动开发网的东东....比较适合我们这种驱动白痴 ^_^注:在测试过程中.因为是命令行模式,所以在任务管理器的应用程序中看的到, 实际上在进程中已经隐藏了...其他的自己改吧...下面是源代码:#include #incl
ENVI遥感技术
记录2024.03.06所遇到的遥感问题
截取系统API调用
在很多情况下,为了测试代码或扩展操作系统的功能,软件开发人员或测试人员必须截取系统函数调用。有一些软件包能够提供该功能,如微软公司的 Detours* 库,或 OK Thinking Software 的 Syringe*。但是从另一个角度而言,开发人员可能希望不需借助第三方软件,自己就能实现该功能。本文描述了函数截取的几种不同方式,并详细介绍了无需使用商业软件包,也不需受 GNU*(通用公
3D缺陷检测实战:从点云处理到工业质检优化
本文深入探讨了3D缺陷检测在工业质检中的实战应用,详细阐述了从点云处理到深度学习模型部署的完整技术链路。文章通过PCB焊点检测等实际案例,分析了3D视觉相比2D检测在识别深度、形状等缺陷方面的优势,并分享了点云滤波、分割、特征提取以及利用YOLOv5等模型进行高效检测的优化心得与落地挑战。
用 ABAP RAP + XCO 把 Excel 导入业务对象:从弹窗 Action 到 EML 落库与附件清理的完整实践
摘要:本文介绍了在SAP RAP框架下实现Excel批量导入功能的完整方案。通过XCO库的XLSX模块解析Excel文件,结合RAP的行为定义和Fiori Elements界面集成,构建了一个支持试运行、数据校验和自动合并的业务导入功能。方案采用RAP标准范式,包括Action参数设计、EML事务处理、附件管理以及异常消息反馈,实现了从文件上传到数据落库的端到端流程,既保证了系统稳定性,又提升了业务用户体验。
截取系统 API 调用(转)
在很多情况下,为了测试代码或扩展操作系统的功能,软件开发人员或测试人员必须截取系统函数调用。有一些软件包能够提供该功能,如微软公司的 Detours* 库,或 OK Thinking Software 的 Syringe*。但是从另一个角度而言,开发人员可能希望不需借助第三方软件,自己就能实现该功能。 本文描述了函数截取的几种不同方式,并详细介绍了无需使用商业软件包,也不需受 GNU*(通用...
LinePhone3.2.7(android端最新版本) sip客户端
SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/
Windows系统调用中API的3环部分
一、R3环API分析的重要性 Windows所提供给R3环的API,实质就是对操作系统接口的封装,其实现部分都是在R0实现的。 很多恶意程序会利用钩子来钩取这些API,从而达到截取内容,修改数据的意图。 现在我们使用olldbg对ReadProcessMemory进行跟踪分析,查看其在R3的实现,并根据我们的分析来重写一个ReadProcessMemory。 重写ReadProcessMe...
温度PID控制PLC程序
温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值
文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况
主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。
JNA 调用windows平台截取屏幕
import java.awt.Dimension; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.DataBuffer; import java.awt.
jre9下载 jdk9
(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】
C# 活动窗体截图:基于 Win32 API 的实现
该截图功能类基于BitBltGDI+user32.dlldwmapi.dllgdi32.dll返回窗口边框矩形(不含阴影等视觉扩展),而能获取实际显示区域,确保截图完整。BitBltBitBlt适用场景与限制BitBlt。
用纯C#实现截取屏幕指定区域
以前在别的地方见过一个通过调用系统API实现屏幕截图的例子,从内心来说我不太喜欢在C#代码中出现这种情况,现在什么都讲“和谐”,我觉得这种做法就是破坏了我们的“和谐”代码,呵呵,开玩笑,有的时候,不通过系统API确实难以做到的。 下面讲述的就是怎么通过纯C#来实现屏幕截图,代码如下: //截取全屏图象privatevoidbtnFullScreen_Click(objectsender,...
基于Tauri与Rust构建跨平台窗口管理工具:从系统API调用到性能优化
窗口管理是提升多任务处理效率的基础技术,其核心原理在于通过操作系统API获取并控制应用程序窗口的状态与内容。在工程实践中,跨平台窗口枚举、实时缩略图生成与低资源占用是实现高效管理工具的技术难点。通过合理的技术选型与架构设计,开发者可以构建轻量级辅助工具,显著提升工作流效率。本文以Tauri框架结合Rust后端为例,深入探讨了如何利用系统级API实现窗口列表获取、智能截图更新策略及前端性能优化,特别针对Electron应用体积过大与实时截图性能损耗等常见痛点,提供了差异更新与缓存机制等解决方案。该方案适用于需
一些常用的API--java小白学习
本文介绍了Java中常用的API和集合操作。主要内容包括:1)API的使用方法,如Scanner和Random类;2)String类的特性及常用方法(比较、遍历、截取、替换等);3)StringBuilder类的高效字符串操作;4)ArrayList集合的创建和增删改查操作。文章通过具体代码示例展示了字符串处理、回文判断、集合筛选等常见场景的应用,并比较了不同数据结构的适用场景。最后提供了多个练习案例,帮助掌握字符串和集合的实际应用。



(DLL Hell)*”为基础,该文章还包括可下载的源代码。在本文附录中可获得
Inject.cpp 和
Inject.h 。已对它们进行了定制以便于集成——仅需将其包括在项目中然后调用
InjectLib 即可。使目标进程加载
DLL 的算法按如下步骤工作:



886



被折叠的 条评论
为什么被折叠?



