MicroSoft编译器你不可不知的秘密
来源:互联网 发布:淘宝上卖的星巴克杯子 编辑:程序博客网 时间:2024/06/11 07:32
标题: 【原创】MicroSoft编译器你不可不知的秘密
作者: 黑猫①号
时间: 2012-12-15 23:33
转载请注明出处 链接: http://blog.csdn.net/jha334201553/article/details/8300153
注:
1. 本文是写给调用dll原理不太清楚,以及不知道怎么调用未声明但是已经导出的windows API(例如Native API),大牛自动略过本文。
2. 一些基础的知识不会介绍,例如什么是函数调用约定(如:__stdcall、__cdecl、__fastcall等),为什么要加extern “C” 、 #ifdef __cplusplus。也不会介绍一些很容易百度(谷歌)到的知识。
用控制台直接编译程序
以下演示内容全部通过控制台编译,在开始之前先大概的说下环境(加这部分是因为本文内容就是有关导出函数环境的O(∩_∩)O~ )。
VC6其实可以免安装使用的,将bin、lib、include文件夹( 如果想要alt、mfc功能,那把他们的文件也一起 )直接复制到U盘中走到哪带到哪,再写个脚本设置下环境变量,就可以随心编译。(PS: 我用的控制台编译,之前我就说过了)。脚本如下形式:
@echo offset path =%path%;%cd%\bin;set include=%cd%\Include;%cd%\MFC\include;%cd%\ATL\Include;set lib=%cd%\lib;%cd%\MFC\Lib;cmd.exe
头文件、lib、dll是怎么回事
a. 头文件
int main(int argc, char* argv){ return 0;}
以上代码直接在控制台编译通过很正常。那以下呢?
int main(int argc, char* argv){ printf(“hello world!\n”); return 0;}
编译器会拒绝编译,显示printf函数未定义,通常的做法是加入stdio.h头文件。可是,如果不加这个头文件呢,可否有方案解决这个文件?答案是:有。
在调用printf之前加入声明、编译时加入msvcrt.lib即可。
#pragma comment(lib, "MSVCRT")#ifdef __cplusplusextern "C" {#endif int printf( const char* format , ... );#ifdef __cplusplus};#endif int main(int argc, char* argv){ printf("hello world!\n"); return 0;}
命令行定位到文件所在位置,然后输入 cl *.cpp 即可编译出exe程序来(虽然有些警告信息o(╯□╰)o )
提示: .h头文件中是各种函数的声明部分,使程序在编译的时候可以找到函数,这样编译阶段就不会报undefined错误了。而lib文件呢,是在链接的时候根据编译阶段生成的obj文件中指明的label到lib文件中找这个函数,如果lib为静态库(是指代码在lib中,而没有生成dll,见示例代码 ),则连接器会把lib中的代码复制到可执行文件中,如果lib是动态库,则从lib文件中找这个函数的导出名与跟这个lib库一起编译出来的动态库名称,写入导入表(动态库中其实只需要两个参数,一个dll名称,一个原函数名称)。
b. Lib与dll文件
自己写一个user32.dll动态库调用里面的MessageBoxA调用会是什么情况呢?
User32.asm内容(以下为汇编版本,在下面的下载包中有个C语言版)
.386 .model flat,stdcall option casemap :none .code;DLL入口DllEntry proc _hInstance,_dwReason,_dwReserved mov eax,1 retDllEntry Endp; 导出函数MessageBoxA proc _dwNumber1:DWORD, _dwNumber2:DWORD, _dwNumber3:DWORD, _dwNumber4:DWORD xor eax,eax retMessageBoxA endp End DllEntry
User32.def文件内容(一些人喜欢用__declspec( dllexport ) 导出函数,我喜欢用def文件申明,这样我的dll可以导出自己想要的任何名字,还可以选择不导出名字)
EXPORTS MessageBoxA
编译命令 ml /c /coff /Cp *.asm
link /section:.bss,S /dll /def:user32.def /subsystem:windows *.obj
生成一个user32.lib,将此文件重命名为myuser32.lib (防止于编译器库中的user32.lib 冲突(原user32.lib 后面有用))。
再创建一个测试的cpp文件:
#pragma comment(lib,"myuser32.lib") #ifdef __cplusplusextern "C" {#endif int __stdcall MessageBoxA(unsigned long, char*, char*, unsigned long ); #ifdef __cplusplus};#endif int main(){ MessageBoxA(0, "你好", "标题栏", 0); return 0;}
编译命令: cl *.cpp
运行下编译出来的程序,呀!糟糕,为什么运行的时候出现了一个MessageBox对话框呢?难道没有调用我们自己写的user32.dll么?但是链接的时候明明是链接我们的lib文件的呀!!!这时候你是不是觉得很奇怪?这个问题留给你了(跟PE格式、系统有关)。(可以参考win loader (注:不是boot loader,是可执行文件加载器))
调用库lib中没有的函数
记得网上一直流传着一个函数叫 SetLayeredWindowAttributes 可以改变窗体,可是调用这个函数的方法都是先LoadLibrary 再 GetProAddress 地址以后调用的,那么可以利用上面调用MessageBoxA的方法去调用这个函数了,再在上面的代码中加入如下代码:
SetLayeredWindowAttributes proc _dwNumber1:DWORD, _dwNumber2:DWORD, _dwNumber3:DWORD, _dwNumber4:DWORD xor eax,eax retSetLayeredWindowAttributes endp
导出函数也相应的加一个SetLayeredWindowAttributes。
编译出user32.lib文件,重新命名为myuser32.lib
再写一个窗体程序,直接加入SetLayeredWindowAttributes声明,myuser32.lib库 后调用,编译通过。
#pragma comment(lib,"myuser32.lib")#pragma comment(lib,"user32.lib") #include <windows.h> #ifdef __cplusplusextern "C" {#endif long WINAPI SetLayeredWindowAttributes( HWND hWnd, int cr, unsigned char bAlpha, unsigned long dwFlags);#ifdef __cplusplus};#endif//…… 略
完整的示例代码见下载包(MicroSoft编译器你不可不知的秘密\自己构建lib文件调用\窗口透明)
调用Native API
所谓的应用层Native API就是ntdll导出的函数。这些函数大部分是直接通过调用门进入系统内核运行的,在ring3中是比较底层的函数(或许自己利用int 0x2e、sysenter进入内核才算底层吧),对于杀毒软件的主动防御有很好的免杀作用(比如ReadProcessMemory,CreateRemoteThread替换成更底层的NtReadVirtualMemory、NtCreateThread可以解决ring3的主动防御、导入表查杀)。所以Native API在安全方面有着重要的作用。
下载包中带了几个ntdll.lib文件(MicroSoft编译器你不可不知的秘密\直接调用ntdll函数\ntdll),可以接加入工程链接,如果发现这个lib中没有的函数,那么利用上面说的方法自己创建一个ntdll.lib文件导入工程。
例子代码中有对NtAllocateVirtualMemory的调用,其他函数方法类似,关于函数的声明直接到wdk文档中找,或者微软在线帮助(把函数名改成Zw开头,如ZwAllocateVirtualMemory)
#pragma once#ifndef __NTDLL__HH_#define __NTDLL__HH_ #pragma comment(lib, "ntdll")#include<windows.h> typedef unsigned long* ULONG_PTR;#define NTSTATUS LONG #ifdef __cplusplusextern"C"{#endif NTSTATUS WINAPINtAllocateVirtualMemory( HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect ); #ifdef __cplusplus};#endif #endif // __NTDLL__HH_可以写个ntdll.h的头文件,以后要用ntdll函数的时候就添加这个头文件,没有的函数就继续加进去,这样这个头文件就日渐的完善了。不过像CreateRemoteThread这种函数在ntdll中实现还是比较蛋疼的,要想让这个函数跟原来的运行效果一样还要下一点功夫才行,涉及的函数涉及的数据相当多,不过奖品也是很丰盛的,你用你自己实现方法,360就不会吭声了。
示例程序下载地址:http://ishare.iask.sina.com.cn/f/35074546.html
- MicroSoft编译器你不可不知的秘密
- MicroSoft编译器你不可不知的秘密
- 网络营销培训分享你不可不知的内链秘密
- 限时免费不可不知的秘密
- 限时免费不可不知的秘密
- 你不可不知的JSON
- 即兴发言,你不可不知“三”点秘密
- 通过Jdbc连Oracle,不可不知的秘密!!
- java中你不可不知的问题
- 你不可不知的美丽含义
- 对于Python,你不可不知的东西
- 你不可不知的Git常用命令
- 你不可不知的HTML优化技巧
- 你不可不知的Eclipse快捷键
- 你不可不知的 HTML 优化技巧
- 你不可不知的HTML优化技巧
- 你不可不知的HTML优化技巧
- 你不可不知的HTML优化技巧
- 数据库的几个概念:主键,外键,索引,唯一索引
- 4个QTI传感器的策略图
- .net中repeater控件使用
- VC++窗口子类化
- Android程序打包成apk
- MicroSoft编译器你不可不知的秘密
- 关闭MyEclipse无用的工具
- 关于GCC中同时使用动态和静态库链接的操作参数和解释
- 入手尼康D7000,初发拍摄小品
- Struts 2的配置文件
- MyEclipse8.0 安装插件的方法
- 公司正式成立两天即以1.76亿美元价格被 Juniper 收购
- .net中gridview控件数据绑定及分页
- [Android实例] Android、iPhone和Java三个平台一致的加密工具