用 VC2012 产生脱离VC运行库的 C/C++ 程序

最近在研究如何使一个VC编译的程序脱离VC运行库,也就是msvcrXX.dll。 查了许多资料,最后确定了两篇可参考文章,不过都是以VC2010为开发环境的,而我用的是VC2012,和他们的有所不同。 首先,要把msvcrXX.dll脱离出来,第一步是取消链接库,代码是:
#pragma comment (linker, "/nodefaultlib:msvcrt.lib") /*If _DEBUG, it should be msvcrtd.lib*/
这样就把msvcrXX.dll去掉了,但是接下来的就问题无限了,比如, mainCRTStartup 函数没了。(这是Console程序,对于Windows程序应该是WinMainCRTStartup)。写过Windows SDK程序的人都知道,对于UNICODE和非UNICODE程序,入口函数是不一样的,为了统一,我们先指定下入口函数。
#pragma comment (linker, "/entry:mainCRTStartup")
此外,没有 CRT 的时候,没法进行基本运行时检查,所以打开“项目属性-C/C++-代码生成”,把“基本运行时检查”改为“默认值”。(Release配置不用改,只改Debug)。 下面是入口函数实现:
#include <Windows.h>
int __cdecl mainCRTStartup() {
    WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "Hello World!\r\n", 14, NULL, NULL);
    return 0;
}
编译运行,Sorry,出错了。错误提示:
  1>main.obj : error LNK2001: 无法解析的外部符号 @__security_check_cookie@4
这个错误提示比较简单解决,只需引入 bufferoverflowU.lib 即可。
#pragma comment (lib,"bufferoverflowU.lib")
这下再编译运行,OK了,此时程序只有 3.5KB 。但是,试试使用malloc?printf?或者是使用C++类?不好意思,这是VC运行库的内容。那么,似乎这么做毫无意义了?那也未必,如果你只是要 C 编程,那么可以把部分函数重写。比如:
void *mem_alloc(ULONG_PTR uSize) {
    return (void *)HeapAlloc (GetProcessHeap(), 0,uSize);
}

void mem_free (LPVOID pMemBlock) {
    HeapFree (GetProcessHeap(), 0, (LPVOID)pMemBlock);
}

void *operator new (size_t uSize) {
    return (void *)HeapAlloc (GetProcessHeap(), 0,uSize);
}

void operator delete (void *pMemBlock) {
    HeapFree (GetProcessHeap(), 0, (LPVOID)pMemBlock);
}

void *operator new[] (size_t uSize) {
    return (void *)HeapAlloc (GetProcessHeap(), 0,uSize);
}

void operator delete[] (void *pMemBlock) {
    HeapFree (GetProcessHeap(), 0, (LPVOID)pMemBlock);
}

DWORD echo(char *pszOutput) { /* Output a string */
    DWORD dwLen;
    dwLen = lstrlenA(pszOutput);
    WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), pszOutput, dwLen, &dwLen, NULL);
    return dwLen;
}
此时测试结果是,C++异常无效(需要在工程设置里把C++异常关掉,否则会提示找不到__CxxFrameHandler3),也就是说,这时  C++ 几乎废了
是否觉得这么做太烦了?其实,msvcrXX.dll是各个版本VC的运行库文件,VC2005开始都要独立安装,但是对于VC6,却几乎不存在这个问题。因为几乎Windows 2000开始的Windows系统都带有VC6的运行库,那么,用它取代掉就可以了!这个比较简单,在VC6安装包里,“VC\Lib\ 目录下,找到MSVCRT.LIB 和 MSVCRTD.LIB。前者是 Release 版本,后者是 Debug 版本,复制到工程目录下,分别命名为 msvcrt98.lib 和 msvcrt98d.lib,然后在代码里写:
#pragma comment (linker, "/nodefaultlib:msvcrt.lib") /* msvcrtd.lib If _DEBUG */
#pragma comment (lib, "msvcrt98.lib") /* msvcrt98d.lib If _DEBUG */
这里,引入了VC6的运行库,那么mainCRTStartup也已经写好了,所以入口函数写 main 即可。而且由于VC6的静态链接库太旧,没有“SAFESEH安全异常处理程序 ”,因此要把“项目属性-链接器-高级-映像具有安全异常处理程序”设置为“ 否 (/SAFESEH:NO) ”。
到此,替代完成。malloc,printf 等 C 标准函数都可以用了。 new,delete 等 C++ 运算符也可以用了,但是 C++ 异常依旧无效。
下面是一份完整代码:
#ifdef _DEBUG
    #pragma comment (linker, "/nodefaultlib:msvcrtd.lib")
    #pragma comment (lib, "msvcrt98d.lib")
#else
    #pragma comment (linker, "/nodefaultlib:msvcrt.lib")
    #pragma comment (lib, "msvcrt98.lib")
#endif

#pragma comment (lib,"bufferoverflowU.lib")

#include <windows.h>
#include <stdio.h>
#include <tchar.h>

class A {
public:
    A(char *pszStr) {
        echo ("New A: ");
        echo (pszStr);
        echo ("\r\n");
    }

    ~A() {
        echo ("Delete A\r\n");
    }

    void print() {
        echo ("A::print()\r\n");
    }
};

int main() {
    A a("Static"), *pa;
    DWORD c;
    char *buf;
    buf = (char*)malloc(123);
    strcpy(buf, "Hello World\r\n");
    printf(buf);
    a.print();
    c = strlen("233213");
    pa = new A("Dynamic");
    pa->print();
    delete pa;
    free(buf);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\Lib 的目录 2009-09-06 16:17 . 2009-09-06 16:17 .. 2006-03-03 23:19 13,712 Bits.Lib 2006-03-03 23:19 4,196 credui.lib 2006-03-03 23:19 57,730 daouuid.lib 2006-03-03 23:19 527,310 ddao35.lib 2006-03-03 23:19 531,012 ddao35d.lib 2006-03-03 23:19 528,038 ddao35u.lib 2006-03-03 23:19 532,702 ddao35ud.lib 2006-03-03 23:19 14,610 WinFax.Lib 2006-03-03 23:19 206,996 GdiPlus.lib 2006-03-03 23:20 27,500 HelpCenterInterfaces.tlb 2006-03-03 23:20 64,608 HelpServiceInterfaces.tlb 2006-03-03 23:21 13,252 p2p.lib 2006-03-03 23:21 11,218 p2pgraph.lib 2006-03-03 23:21 1,380,352 atlsd.pdb 2006-03-03 23:23 121,974 WiaGuid.Lib 2006-03-03 23:23 19,212 WiaScr.Tlb 2006-03-03 23:23 10,152 esebcli2.lib 2006-03-03 23:23 129,732 cdoex.tlb 2006-03-03 23:23 26,608 cdoexm.tlb 2006-03-03 23:23 10,832 exevtsnk.tlb 2006-03-03 23:23 7,888 ActiveDS.Lib 2006-03-03 23:23 99,122 ADSIid.Lib 2006-03-03 23:23 53,222 Wldap32.Lib 2006-03-03 23:23 55,600 CDOSys.Tlb 2006-03-03 23:23 6,254 certadm.lib 2006-03-03 23:23 217,676 certidl.lib 2006-03-03 23:23 59,044 Crypt32.Lib 2006-03-03 23:23 5,516 ComSvcs.Lib 2006-03-03 23:23 75,386 DtcHelp.Lib 2006-03-03 23:23 2,106 Mtx.Lib 2006-03-03 23:23 1,734 mtxdm.lib 2006-03-03 23:23 121,030 Svcguid.Lib 2006-03-03 23:23 63,400 xaSwitch.Lib 2006-03-03 23:23 3,364 xoleHlp.Lib 2006-03-03 23:23 6,402 Icm32.Lib 2006-03-03 23:23 1,978 Icmui.Lib 2006-03-03 23:23 17,036 Mscms.Lib 2006-03-03 23:23 620,890 MMC.Lib 2006-03-03 23:23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值