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的混淆技术与虚拟化技术,能够全面保护代码逻辑。