首先是:
我的testing系统:Windows 7 32位专业版Windows 7 64位专业版
编译器:gcc版本5.2.0(i686-win32-dwarf-rev0,由MinGW-W64项目build造)
构build选项:g ++ foo.cpp -o foo.exe
如何检测内存数据更改?
如何获得过去10年的夏令时间界限
相当于GetCommandLine和CommandLinetoArgv的Linux?
在Windows关机时,Windows服务如何运行?
如何以编程方式确定二进制输出中的构build系统等价性?
我的应用程序dynamic地从kernel32.dll接收函数地址。 这按预期工作。 但是,当我对这些API调用进行异或encryption并将解密的string传递给GetProcAdress函数时,取决于stringpVAE_D [strlen(pVAE_E)]的顺序。 和char pGTC_D [strlen(pGTC_E)]以及encryptionstring的顺序; 如果在char pVAE_D [strlen(pVAE_E)]之前设置字符pGTC_D [strlen(pGTC_E)](对于encryption的string是相同的)
`#include <windows.h> #include <stdio.h> typedef BOOL(WINAPI* _Getthreadcontext) (HANDLE hThread,LPCONTEXT lpContext ); typedef LPVOID(WINAPI* _VirtualAllocEx) (HANDLE handle_Process,LPVOID longpointer_Address,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect ); void encrStr(char *pStr,int len,char *pOut,char cryptochar); int main(void) { char pVAE_E[] = {0x32,0x0d,0x16,0x10,0x11,0x05,0x08,0x25,0x0b,0x07,0x21,0x1c,0x00}; // VirtualAllocEx encrypted with d char pGTC_E[] = { 0x3d,0x1f,0x0e,0x2e,0x12,0x1b,0x1e,0x39,0x15,0x14,0x02,0x00}; // Getthreadcontext encrypted with z char pVAE_D[strlen(pVAE_E)]; char pGTC_D[strlen(pGTC_E)]; encrStr(pVAE_E,strlen(pVAE_E),pVAE_D,'d'); encrStr(pGTC_E,strlen(pGTC_E),pGTC_D,'z'); HMODULE hKernel32 = LoadLibraryA("kernel32.dll"); FARPROC fpGetthreadcontext = GetProcAddress(hKernel32,pGTC_D); if (fpGetthreadcontext == NULL) { printf("gtc Failed.n"); } _Getthreadcontext kernel32Getthreadcontext = (_Getthreadcontext)fpGetthreadcontext; FARPROC fpVirtualAllocEx = GetProcAddress(hKernel32,pVAE_D); if (fpVirtualAllocEx == NULL) { printf("vae Failed.n"); } _VirtualAllocEx kernel32VirtualAllocEx = (_VirtualAllocEx)fpVirtualAllocEx; } void encrStr(char *pStr,char cryptochar) { // zero char must remain,therefore i < len for (int i = 0; i < len; i++) { pOut[i] = pStr[i] ^ cryptochar; printf("%cn",pOut[i]); } pOut[len] = 0x00; printf("%sn",pOut); }`
如果我将解密缓冲区的内存大小增加1,它将独立于分配顺序。 为什么它在其他方面失败?
如何停止具有多个线程的Windows服务无法停止
WM_QUIT只发布线程而不是窗口?
升压asio计时器不阻止读取呼叫
这是你的代码的两个问题。 首先,您正在使用strlen来确定解密字符串的缓冲区的大小。 这个函数不考虑空终止符字符' 0'(在你的情况下是0x00)。 这意味着缓冲区pVAE_D和pGTC_D一个元素比包含加密字符串的相应缓冲区少一个元素。 第二个问题是你的encrStr函数。 在这个例子中,你正在使用语句pOut[len] = 0x00;来写入超出数组的范围pOut[len] = 0x00; 。 访问数组的索引在[0,len – 1]的范围内。 这就是你的函数(假设你正在传递一个输出缓冲区,其中有足够的字符串元素和它的空终止符)应该被执行:
void encrStr(char *pStr,therefore i < len for (int i = 0; i < len - 1; i++) { pOut[i] = pStr[i] ^ cryptochar; printf("%cn",pOut[i]); } pOut[len - 1] = 0x00; printf("%sn",pOut); }
当你写入超出数组范围的时候,你正在破坏你的数组的堆栈,并且遇到UB(未定义的行为)。 这就是为什么这个样本有时会起作用,而有些时候却不行。 有些编译器会提醒你这个,但其他编译器则不会。 这些在C ++中是微妙的错误,可能会导致你很多头痛。 查看这些链接,了解更多关于未定义行为的信息:
C ++程序员应该知道的所有常见的未定义行为是什么?
https://en.wikipedia.org/wiki/Undefined_behavior