【问题标题】:Encrypted API Call failing加密 API 调用失败
【发布时间】:2016-01-15 19:23:06
【问题描述】:

第一件事:

我的测试系统:Windows 7 32 位专业版 Windows 7 64 位专业版

编译器: gcc 5.2.0版(i686-win32-dwarf-rev0,由MinGW-W64项目构建)

编译选项:g++ foo.cpp -o foo.exe

我的应用程序从 kernel32.dll 动态接收函数地址。 这按预期工作。但是,当我对这些 API 调用进行异或加密并将解密的字符串传递给 GetProcAdress 函数时,它会失败,具体取决于 char pVAE_D[strlen(pVAE_E)]; 的顺序。和 char pGTC_D[strlen(pGTC_E)] 以及加密字符串的顺序;如果我在 char pVAE_D[strlen(pVAE_E)] 之前设置 char pGTC_D[strlen(pGTC_E)] (加密字符串相同)

`#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, 0x08, 0x08,   

0x0b, 0x07, 0x21, 0x1c, 0x00};  // VirtualAllocEx encrypted with d

char pGTC_E[] = {
0x3d, 0x1f, 0x0e, 0x2e, 0x12, 0x08, 0x1f, 0x1b, 0x1e, 0x39, 0x15, 0x14, 
0x0e, 0x1f, 0x02, 0x0e, 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, int len, char *pOut, char cryptochar)
{
// zero char must remain, therefore i < len
for (int i = 0; i < len; i++)
{
    pOut[i] = pStr[i] ^ cryptochar; 
    printf("%c\n", pOut[i]); 
}
pOut[len] = 0x00; 
printf("%s\n", pOut); 
}`

如果我将解密缓冲区的内存大小增加 1,它的工作原理与分配顺序无关。为什么它会在 else 中失败?

【问题讨论】:

  • 请从您的问题中去除不相关的信息和代码,并专注于您遇到的问题。请提供MCVE(强调minimal)。对LoadLibraryAGetProcAddress 的调用以及相关的函数指针调用与问题完全无关。
  • 通常pOut[len] 是无效索引。最后一个元素应该是pOut[len - 1]

标签: c windows winapi encryption


【解决方案1】:

您的代码存在两个问题。首先是您使用strlen 来确定缓冲区的大小 解密的字符串。此函数不考虑空终止符“\0”(在您的 案子)。这意味着缓冲区pVAE_DpGTC_D 将比它们对应的元素少一个 包含加密字符串的缓冲区。第二个问题是你的encrStr 函数。在里面,你在写超越 声明 pOut[len] = 0x00; 的数组边界。访问数组的索引在 [0, len - 1] 范围内。 这就是您的函数的方式(假设您正在传递一个输出缓冲区,其中包含足够的字符串元素及其 空终止符)应该被实现:

void encrStr(char *pStr, int len, char *pOut, char cryptochar)
{
    // zero char must remain, therefore i < len
    for (int i = 0; i < len - 1; i++)
    {
        pOut[i] = pStr[i] ^ cryptochar; 
        printf("%c\n", pOut[i]); 
    }
    pOut[len - 1] = 0x00; 
    printf("%s\n", pOut); 
}

当你写超出数组的边界时,你正在破坏你的数组周围的堆栈,你会遇到 UB (未定义的行为)。这就是为什么此示例有时有效,有时无效的原因。一些编译器会 警告你这一点,但其他人不会。这些是 C++ 中的细微错误,可能会让您非常头疼。查看 这些链接了解有关未定义行为的更多信息:

What are all the common undefined behaviours that a C++ programmer should know about?

https://en.wikipedia.org/wiki/Undefined_behavior

【讨论】:

  • 谢谢,这几乎解决了这个问题,我明白为什么它现在失败了。我用你改进的代码示例重新编译了它,它工作正常。
猜你喜欢
  • 1970-01-01
  • 2023-01-30
  • 2012-08-19
  • 2014-07-01
  • 2020-12-17
  • 2014-02-15
  • 2021-06-12
  • 2023-03-31
  • 1970-01-01
相关资源
最近更新 更多