C++ 安全编程

C++ 语言优势

C++ 编译生成的原生程序(Native Code)直接运行在硬件上,相比虚拟机或解释器环境中的代码,逆向工程难度大幅提升。由于原生程序的机器码结构复杂且缺乏高级语义信息,攻击者在分析程序时面临天然屏障,增加了获取敏感信息的难度。

然而,虽然“难以逆向”能提高安全性,但并不代表“无法逆向”。真正的安全性来源于开发者的安全意识和主动的防护措施。在代码设计的早期阶段就考虑安全因素,是构建强健系统的基础。

C++ 强大的元编程能力,尤其是模板元编程,为安全编程提供了独特优势。通过元编程,开发者可以:

  • 编译时安全检查:借助模板约束和静态断言,开发者可以在编译阶段捕获类型错误、接口误用等潜在风险,从而避免在运行时出现问题。
  • 类型安全抽象:通过设计精妙的模板库,开发者可以创建既安全又可复用的组件,减少手动编写易错代码,降低底层错误的发生。
  • 安全性与效率兼得:元编程将运行时计算转移到编译时,不仅提升了程序性能,还减少了攻击者可以利用的复杂执行路径,从而进一步增强了安全性。

因此,C++ 不仅能够高效编写安全代码,还能在保证安全的前提下,提升开发效率和程序性能。二者并不冲突,C++ 开发者可以通过智能的编程方法同时确保代码的安全性与高效性。

安全编程技巧

接下来,我将介绍两种非常实用的安全编程技巧:隐藏敏感字符串和隐藏导入函数。这些技巧能够有效防止逆向工程者轻松获取程序中的敏感信息,从而大幅提升代码的安全性。需要注意的是,以下提供的代码仅供参考,测试环境为Windows 11 64位系统。

隐藏敏感字符串

C++实现代码

#include <iostream>
#include <utility>
#include <type_traits>
#include <array>

#ifdef _MSC_VER
#define FORCEINLINE __forceinline
#else
#define XORSTR_FORCEINLINE __attribute__((always_inline)) inline
#endif

#define vb_xorstr(str) ::vb::xor_str([]() { return str; }, std::integral_constant<std::size_t, sizeof(str) / sizeof(*str)>{}, std::make_index_sequence<sizeof(str)>{})
#define vb_xorstr_once(str) vb_xorstr((str)).crypt_get()

namespace vb {

 namespace detail {

   template<std::size_t S>
   FORCEINLINE constexpr std::uint8_t key()
  {
     return std::uint8_t(S + (__TIME__[1] ^ __TIME__[7]));
  }

   template<class T>
   FORCEINLINE constexpr std::uint8_t
     xored_bytes(std::uint8_t key, std::size_t idx, const T* str) noexcept
  {
     return str[idx] ^ key;
  }
}

 template<std::size_t Size, class keys, class indexes >
 class xor_str;

 template< std::size_t Size, std::uint8_t... keys, std::size_t... indexes >
 class xor_str< Size, std::integer_sequence<std::uint8_t, keys...>, std::index_sequence<indexes ...>> {

    std::uint8_t buffer_[sizeof...(keys)];

 public:
   using pointer = char*;

   template<class L>
   FORCEINLINE xor_str(L l, std::integral_constant<std::size_t, Size>, std::index_sequence<indexes ...>) noexcept
    : buffer_{ (std::integral_constant<std::uint8_t, detail::xored_bytes(keys, indexes, l())>::value)... }
  {}

   FORCEINLINE constexpr std::size_t size() const noexcept
  {
     return Size - 1;
  }

   FORCEINLINE pointer crypt_get() noexcept
  {
     std::uint8_t key[]{ keys... };

     for (int i = 0; i < Size;++i)
    {
       buffer_[i] ^= key[i];
    }
     return (pointer)(buffer_);
  }
};

 template<class L, std::size_t Size, std::size_t... indexes>
 xor_str(L l, std::integral_constant<std::size_t, Size>, std::index_sequence<indexes...>) -> xor_str<
   Size,
   std::integer_sequence<std::uint8_t, detail::key<indexes>()...>,
   std::index_sequence<indexes...>>;

} // namespace vb

反编译对比

测试代码


void test_xorstr()
{
 string userName, password;

 cout << "Enter username: ";
 cin >> userName;

 cout << "Enter password: ";
 cin >> password;

 if (verifyAccount(userName, "5e884898da", password))
{
   cout << "Verification Successful" << endl;
   cout << "   /\\_/\\   " << endl;
   cout << "   ( o.o ) " << endl;
   cout << "   > ^ <   " << endl;
   cout << " You got a kitten!" << endl;
}
 else
{
   cout << "Verification Failed" << endl;
}

 cin.ignore();
 getchar();
}

void test_xorstr2()
{
 string userName, password;

 cout << vb_xorstr_once("Enter username: ");
 cin >> userName;

 cout << vb_xorstr_once("Enter password: ");
 cin >> password;

 if (verifyAccount(userName, vb_xorstr_once("5e884898da"), password))
{
   cout << vb_xorstr_once("Verification Successful") << endl;
   cout << vb_xorstr_once("   /\\_/\\   ") << endl;
   cout << vb_xorstr_once("   ( o.o ) ") << endl;
   cout << vb_xorstr_once("   > ^ <   ") << endl;
   cout << vb_xorstr_once(" You got a kitten!") << endl;
}
 else
{
   cout << vb_xorstr_once("Verification Failed") << endl;
}

 cin.ignore();
 getchar();
}

未隐藏字符串

隐藏字符串

隐藏导入函数

C++实现代码

#include <iostream>
#include <utility>
#include <type_traits>
#include <array>
#include <map>
#include <vector>
#include <Windows.h>


namespace vb {
 class importer
{
 public:
   importer()
  {
     
  }

   bool preloadModule(char* moduleName)
  {
     auto h = GetModuleHandleA(moduleName);
     if(!h)
       h = LoadLibraryA(moduleName);

     if(!h)
       return false;

     moudle_list_.push_back(h);
  }

   template<typename Ret, typename... Args>
   Ret solve(const char* api, Args... args)
  {
     using FuncPtr = Ret(*)(Args...);
     auto iter = api_cache_map_.find(api);
     if(iter != api_cache_map_.end())
       return (reinterpret_cast<FuncPtr>(iter->second))(std::forward<Args>(args)...);  

     void* address = NULL;
     for (const auto& m : moudle_list_)
    {

       address = GetProcAddress((HMODULE)m, api);
       if (address)
         break;
    }

     if (!address)
    {
       abort();
       return {};
    }
       
     api_cache_map_.insert({api,address });
     return (reinterpret_cast<FuncPtr>( address))(std::forward<Args>(args)...);
  }

 private:
   std::map<string, void*> api_cache_map_;
   std::vector<void*> module_list_;
};

} // namespace vb

反编译对比

测试代码


void test_importer()
{
 string userName, password;

 HANDLE hConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
 HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
 DWORD dwRead, dwWritten;
 CHAR chBuf[1024];


 const char* prompt = "Enter username: ";
 WriteConsoleA(hConsoleOutput, prompt, strlen(prompt), &dwWritten, NULL);

 BOOL bSuccess = ReadConsoleA(hConsoleInput, chBuf, sizeof(chBuf), &dwRead, NULL);
 if (bSuccess)
   userName = string(chBuf, dwRead - 2);

 prompt = "Enter password: ";
 WriteConsoleA(hConsoleOutput, prompt, strlen(prompt), &dwWritten, NULL);

 bSuccess = ReadConsoleA(hConsoleInput, chBuf, sizeof(chBuf), &dwRead, NULL);
 if (bSuccess)
   password = string(chBuf, dwRead - 2);

 string key = "5e884898da";
 if (verifyAccount(userName, key, password))
{
   MessageBoxA(NULL, "Verification Successful", "Result", MB_OK);

   const char* kitten = "   /\\_/\\   \n   ( o.o ) \n   > ^ <   \n You got a kitten!\n";
   WriteConsoleA(hConsoleOutput, kitten, strlen(kitten), &dwWritten, NULL);
}
 else
{
   MessageBoxA(NULL, "Verification Failed", "Result", MB_OK);
}
}

void test_importer2()
{
 auto importer = vb::importer();

 importer.preloadModule(vb_xorstr_once("user32.dll"));
 importer.preloadModule(vb_xorstr_once("Kernel32.dll"));
 auto WriteConsoleAPtr = importer.solve<BOOL, HANDLE, CONST VOID*, DWORD, LPDWORD, LPVOID>(vb_xorstr_once("WriteConsoleA"));
 auto ReadConsoleAPtr = importer.solve<BOOL, HANDLE, LPVOID, DWORD, LPDWORD, PCONSOLE_READCONSOLE_CONTROL>(vb_xorstr_once("ReadConsoleA"));
 auto MessageBoxAPtr = importer.solve<int, HWND, LPCSTR, LPCSTR, UINT>(vb_xorstr_once("MessageBoxA"));
 auto GetStdHandlePtr = importer.solve<HANDLE, DWORD>(vb_xorstr_once("GetStdHandle"));

 string userName, password;
 HANDLE hConsoleInput = GetStdHandlePtr(STD_INPUT_HANDLE);
 HANDLE hConsoleOutput = GetStdHandlePtr(STD_OUTPUT_HANDLE);
 DWORD dwRead, dwWritten;
 CHAR chBuf[1024];

 const char* prompt = vb_xorstr_once("Enter username: ");
 WriteConsoleAPtr(hConsoleOutput, prompt, strlen(prompt), &dwWritten, NULL);

 BOOL bSuccess = ReadConsoleAPtr(hConsoleInput, chBuf, sizeof(chBuf), &dwRead, NULL);
 if (bSuccess)
   userName = string(chBuf, dwRead - 2);

 prompt = vb_xorstr_once("Enter password: ");
 WriteConsoleAPtr(hConsoleOutput, prompt, strlen(prompt), &dwWritten, NULL);

 bSuccess = ReadConsoleAPtr(hConsoleInput, chBuf, sizeof(chBuf), &dwRead, NULL);
 if (bSuccess)
   password = string(chBuf, dwRead - 2);

 string key = vb_xorstr_once("5e884898da");
 if (verifyAccount(userName, key, password))
{
   MessageBoxAPtr(NULL, vb_xorstr_once("Verification Successful"), vb_xorstr_once("Result"), MB_OK);

   const char* kitten = vb_xorstr_once("   /\\_/\\   \n   ( o.o ) \n   > ^ <   \n You got a kitten!\n");
   WriteConsoleAPtr(hConsoleOutput, kitten, strlen(kitten), &dwWritten, NULL);
}
 else
{
   MessageBoxAPtr(NULL, vb_xorstr_once("Verification Failed"), vb_xorstr_once("Result"), MB_OK);
}
}

未隐藏导入函数

隐藏导入并且隐藏字符串

代码保护工具推荐

尽管上述两种方式可以在一定程度上增强代码的安全性,但仍不足以满足高要求的安全防护需求。开发人员不仅需要关注业务逻辑,还必须兼顾代码的安全性,这对开发人员的要求相当高。为此,推荐一款专注于Native代码安全的防护工具——Virbox Protector。该工具提供了SDK,支持数据加解密,并能有效保护导入表。通过将开发与安全防护分离,它不仅不影响开发效率,还能有效确保代码安全性。此外,Virbox Protector的混淆技术与虚拟化技术,能够全面保护代码逻辑。

滚动至顶部
售前客服
周末值班
电话

电话

13910187371