• 滴水逆向-静态链接库与动态链接库





    相关测试代码

    代码复用的实现:
    
    1.静态链接库
    
    
    一,创建静态链接库:
    
    (1)在VC6中创建项目:Win32 Static Library
    (2)在项目中创建两个文件:cntftools.h 和 cntftools.cpp; 这里创建两个文件就是上面操作完成之后,直接新建一个class即可生成这两文件;
    
    cntftools.h文件:
    
    #if !defined(AFX_TEST_H__DB32E837_3E66_4BE7_B873_C079BC621AF0__INCLUDED_)
    #define AFX_TEST_H__DB32E837_3E66_4BE7_B873_C079BC621AF0__INCLUDED_
    
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    
    int Plus(int x, int y);
    int Sub(int x, int y);
    int Mul(int x, int y);
    int Div(int x, int y);
    
    #endif
    
    cntftools.cpp文件:
    
    int Plus(int x, int y)
    {
    	return x+y;
    }
    int Sub(int x, int y)
    {
    	return x-y;
    }
    int Mul(int x, int y)
    {
    	return x*y;
    }
    int Div(int x, int y)
    {
    	return x/y;
    }
    
    3.编译  --- 点击编译即可,不需要执行,调试等其他操作;
    
    
    
    二,使用静态链接库:
    
    方式一:
    (1)将上面编译完成之后,生成的cntftools.h 和 cntflibs.lib复制到要使用的项目中,这里放的位置是生成项目的文件夹,不是debug
    文件夹里面;
    
    (2)在需要使用的文件中包含:#include "cntftools.h"
    
    (3)在需要使用的文件中包含:#pragma comment(lib, "cntflibs.lib")
    
    
    (4)下面是重新生成的一个项目文件,然后放入上面的头文件和lib文件,编译成功可正常执行,下面是对应的代码
    
    // sjlx.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <stdlib.h>
    #include "cntftools.h"
    
    
    #pragma comment(lib,"cntflibs.lib")
    
    int main()
    {
        int x = Plus(2,3);
        printf("%d
    ",x);
    	system("pause");
    	return 0;
    }
    
    方式二:
    
    (1)将上面编译完成之后,生成的cntftools.h 和 cntflibs.lib复制到要使用的项目中,这里放的位置是生成项目的文件夹,不是debug
    文件夹里面;
    
    (2)在需要使用的文件中包含:#include "cntftools.h";
    
    (3)在项目名称中右键-->设置-Link-->找到Object/library Module 在最后面空格一下,添加cntflibs.lib;下面是最终的结果;
    kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib、
     advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  cntflibs.lib
    
    
    (4)再次编译执行,可成功运行;
    
    
    三,静态链接库的缺点:
    
    (1)使用静态链接生成的可执行文件体积较大,造成浪费;
    (2)我们常用的printf、memcpy、strcpy等就来自这种静态库	;
    (3)最重要的原因就是因为生成的函数对应代码是在变成成功之后的exe里面,所以如果要更改lib的话,很麻烦,需要;
    需要再次重新编译生成exe文件;验证这一点,可以通过执行此函数的过程中查看反汇编代码;发现生成的反汇编代码;
    其对应的内存地址是带入了ImageBase:0x00400000;
    
    
    2.动态链接库
    
    一,创建DLL
    
    (1)在VC6中创建项目:Win32 Dynamic-Link Library ,名称写dtljkcntf
    (2)再在项目中创建两个文件:mydll.h 和 mydll.cpp; 这里创建两个文件就是,直接新建一个class即可生成这两文件
    
    1.源文件中
    
    int __stdcall Plus(int x,int y)
    {
    	return x+y;
    }
    int __stdcall Sub(int x,int y)
    {
    	return x-y;
    }
    int __stdcall Mul(int x,int y)
    {
    	return x*y;
    }
    int __stdcall Div(int x,int y)
    {
    	return x/y;
    }
    
    2.头文件中
    
    extern "C" _declspec(dllexport) __stdcall int Plus (int x,int y);
    extern "C" _declspec(dllexport) __stdcall int Sub (int x,int y);
    extern "C" _declspec(dllexport) __stdcall int Mul (int x,int y);
    extern "C" _declspec(dllexport) __stdcall int Div (int x,int y);
    
    说明:
    
    1.extern 表示这是个全局函数,可以供各个其他的函数调用;
    
    2."C" 按照C语言的方式进行编译、链接
    
    __declspec(dllexport)告诉编译器此函数为导出函数;
    
    
    二,使用DLL
    
    方式一:隐式连接
    
    步骤1:将 *.dll  *.lib 放到工程目录下面
    
    步骤2:将 #pragma comment(lib,"DLL名.lib") 添加到调用文件中
    
    步骤3:加入函数的声明 --这里就是加在项目对应的主程序代码里面,我这里测试就在main函数入口的代码上面;
    
    extern "C" __declspec(dllimport) __stdcall int Plus (int x,int y);
    extern "C" __declspec(dllimport) __stdcall int Sub (int x,int y);
    extern "C" __declspec(dllimport) __stdcall int Mul (int x,int y);
    extern "C" __declspec(dllimport) __stdcall int Div (int x,int y);
    
    说明:
    
    __declspec(dllimport)告诉编译器此函数为导入函数;
    
    下面是成功执行的主测试代码;
    
    #include "stdafx.h"
    #include <stdlib.h>
    
    __declspec(dllimport) int Plus (int x,int y);
    __declspec(dllimport) int Sub (int x,int y);
    __declspec(dllimport) int Mul (int x,int y);
    __declspec(dllimport) int Div (int x,int y);
    
    #pragma comment(lib,"dtljkcntf.lib")
    
    int main()
    {
        int x = Plus(2,3);
        printf("%d
    ",x);
    	system("pause");
    	return 0;
    }
    
    上面需要注意的地方:
    因为我测试编译生成dll和lib文件之前写的代码是没有带入extern "C" 和__stdcall这两个关键字;
    当然上面是为了测试,实际情况需要带入是最好的;
    测试结果是告诉我们,如果不带入上面两个关键字,那么编译生成的函数名称编译器会给我们重新命名;
    简单理解操作就会给添加一些奇怪的字符,目的就是为了防止函数重名,因为在C++里面有重载的说法;
    如果函数重名会导致其他异常情况;
    所以总结一下:在生成dll和lib之前我们写的什么关键字代码,那么这里就要写什么;
    
    查看dll文件显示函数信息:
    使用工具可以是微软VC6.0 ++ 自带的Dependency进行查看;
    也可以用OD查看,点击按钮"E"; 使用OD查看的时候,记得要要把上面生成好的dtljkcntf.dll文件放在;
    可执行程序exe的相同目录下测试查看验证;
    
    下面是带入extern "C" 和__stdcall关键字的操作;
    
    #include "stdafx.h"
    #include <stdlib.h>
    
    extern "C" __declspec(dllimport) __stdcall int Plus (int x,int y);
    extern "C" __declspec(dllimport) __stdcall int Sub (int x,int y);
    extern "C" __declspec(dllimport) __stdcall int Mul (int x,int y);
    extern "C" __declspec(dllimport) __stdcall int Div (int x,int y);
    
    #pragma comment(lib,"dtljkcntf.lib")
    
    int main()
    {
        int x = Plus(998,663);
        printf("%d
    ",x);
    	system("pause");
    	return 0;
    }
    
    
    方式二:显示链接
    
    步骤1:	//定义函数指针
    		typedef int (__stdcall *lpPlus)(int,int);
    		typedef int (__stdcall *lpSub)(int,int);
    		typedef int (__stdcall *lpMul)(int,int);
    		typedef int (__stdcall *lpDiv)(int,int);
    
    步骤2:  //声明函数指针变量
    		lpPlus myPlus;
    		lpSub mySub;
    		lpMul myMul;
    		lpDiv myDiv;
    
    	步骤3:  //	//动态加载dll到内存中
    		HINSTANCE   hModule = LoadLibrary("DllDemo.dll");
    
    	步骤4:  //获取函数地址
    		myPlus = (lpPlus)GetProcAddress(hModule,   "_Plus@8");
    		mySub = (lpSub)GetProcAddress(hModule,   "_Sub@8");
    		myMul = (lpMul)GetProcAddress(hModule,   "_Mul@8");
    		myDiv = (lpDiv)GetProcAddress(hModule,   "_Div@8");
    
    
    	步骤5:	//调用函数
    		int a = myPlus(10,2);
    		int b = mySub(10,2);
    		int c = myMul(10,2);
    		int d = myDiv(10,2);
    
    
    上述操作完成之后,对应的可执行代码如下:
    
    #include "stdafx.h"
    #include <stdlib.h>
    #include <windows.h>
    //#include <string.h>
    
    //定义函数指针;
    typedef int (__stdcall *lpPlus)(int,int);
    typedef int (__stdcall *lpSub)(int,int);
    typedef int (__stdcall *lpMul)(int,int);
    typedef int (__stdcall *lpDiv)(int,int);
    
    //上面的*lpPlus *lpSub *lpMul *lpDiv都是指针类型;
    
    int main()
    {
        //在main函数里面声明函数指针变量;
        lpPlus myPlus;
        lpSub mySub;
        lpMul myMul;
        lpDiv myDiv;
    
        //动态加载dll到内存中;
        HINSTANCE   hModule = LoadLibrary("dtljkcntf.dll");
    
        //获取函数地址;
        myPlus = (lpPlus)GetProcAddress(hModule,   "_Plus@8");
        mySub = (lpSub)GetProcAddress(hModule,   "_Sub@8");
        myMul = (lpMul)GetProcAddress(hModule,   "_Mul@8");
        myDiv = (lpDiv)GetProcAddress(hModule,   "_Div@8");
    
        int x = myPlus(998,3);
        printf("%d
    ",x);
    	system("pause");
    	return 0;
    }
    
    特别说明:
    
    Handle 是代表系统的内核对象,如文件句柄,线程句柄,进程句柄。
    
    HMODULE 是代表应用程序载入的模块
    
    HINSTANCE 在win32下与HMODULE是相同的东西 Win16 遗留
    
    HWND 是窗口句柄
    
    其实就是一个无符号整型,Windows之所以这样设计有2个目的:
    
    (1)可读性更好
    (2)避免在无意中进行运算
    
    
    3.使用.def导出
    
    下面两步操作之前,先要新建一个动态链接库的文件模板,这里操作跟上面一样,为这里新建的名称是dtljkdef;
    然后生成下面.h和.cpp这两个后缀的名字就是新建class操作即可;
    
    (1)dtdef.h文件
    
    int Plus (int x,int y);
    int Sub (int x,int y);
    int Mul (int x,int y);
    int Div (int x,int y);
    
    (2)dtdef.cpp文件
    
    int Plus(int x,int y)
    {
    	return x+y;
    }
    int Sub(int x,int y)
    {
    	return x-y;
    }
    int Mul(int x,int y)
    {
    	return x*y;
    }
    int Div(int x,int y)
    {
    	return x/y;
    }
    
    (3)cntfdefs.def文件  ---> 这一步操作就是新建一个文本文件,我这的名称是cntfdefs.def(New - Text File)写入下面文件;
    需要注意:这里新建这个文本的时候,要带上后再名称def,然后要勾选上面的添加到项目的复选框,否则编译没问题使用,有问题;
    
    EXPORTS
    
    Plus   	@12
    Sub	    @15 NONAME
    Mul    	@13 NONAME
    Div    	@16
    
    上述的NONAME就是隐藏名字的意思,为这里隐藏了减法和乘法
    
    (4)编译;编译完成之后复制dll文件到需要使用此dll文件的项目文件夹里面即可;
    
    (4)使用序号导出的好处:
    名字是一段程序就精华的注释,通过名字可以直接猜测到函数的功能
    
    通过使用序号,可以达到隐藏的目的.
    
    

    动态链接库dll测试效果



    将生成的dll和lib文件拷贝到新建的一个项目里面

    使用显示链接的方式调用dll


    dll内容


    迷茫的人生,需要不断努力,才能看清远方模糊的志向!
  • 相关阅读:
    POJ-2478 Farey Sequence(欧拉函数)
    BZOJ-1103: [POI2007]大都市meg(树状数组)
    NOIP2016模拟 星际争霸(二分)
    HDU-1222 Wolf and Rabbit (欧几里得定理)
    POJ-2689 Prime Distance(线性筛法)
    FZU-2134 上车(树状数组)
    FZU-2236 第十四个目标(树状数组)
    2016年11月12日00:14:27
    FZU-1921 栀子花开(线段树)
    BZOJ3132 上帝造题的七分钟
  • 原文地址:https://www.cnblogs.com/autopwn/p/15304905.html
Copyright © 2020-2023  润新知