如何查看.dll动态文件里面的函数,方法

如何查看.dll动态文件里面的函数,方法,第1张

可以通过反汇编来知道接口函数参数,建议使用W32DSM来分析,也可以直接使用VC来分析,就是麻烦一点。

现在使用W32DSM来具体说明:

1。先打开需要分析的DLL,然后通过菜单功能-》出口来找到需要分析的函数,双击就可以了。它可以直接定位到该函数。

2。看准该函数的入口,一般函数是以以下代码作为入口点的。

push ebp

mov ebp, esp

3。然后往下找到该函数的出口,一般函数出口有以下语句。

ret xxxx;//其中xxxx就是函数差数的所有的字节数,为4的倍数,xxxx除以4得到的结果

就是参数的个数。

其中参数存放的地方:

ebp+08 //第一个参数

ebp+0C //第二个参数

ebp+10 //第三个参数

ebp+14 //第四个参数

ebp+18 //第五个参数

ebp+1C //第六个参数

。。。。

-------------------------------------------

还有一种经常看到的调用方式:

sub esp,xxxx //开头部分

//函数的内容

。。。

//函数的内容

add esp,xxxx

ret //结尾部分

其中xxxx/4的结果也是参数的个数。

-------------------------------------------------

还有一种调用方式:

有于该函数比较简单,没有参数的压栈过程,

里面的

esp+04就是第一个参数

esp+08就是第二个参数

。。。

esp+xx就是第xx/4个参数

你说看到的xx的最大数除以4后的结果,就是该函数所传递的参数的个数。

----------------------------------------------

到现在位置,你应该能很清楚的看到了传递的参数的个数。至于传递的是些什么内容,还需要进一步的分析。

最方便的办法就是先找到是什么软件在调用此函数,然后通过调试的技术,找到该函数被调用的地方。一般都是PUSH指令

来实现参数的传递的。这时可以看一下具体是什么东西被压入堆栈了,一般来说,如果参数是整数,一看就可以知道了,

如果是字符串的话也是比较简单的,只要到那个地址上面去看一下就可以了。

如果传递的结构的话,没有很方便的办法解决,就是读懂该汇编就可以了。

另外由于编译器的优化原因,可能有的参数没有我前面说的那么简单。如果在该DLL的某个函数中,有关于API调用的话,

并且调用API的参数整好有一个或多个是该DLL函数的参数的话。那么就可以很容易的知道该DLL函数的参数了。

举例说明:以下汇编代码通过W32DSM得到。

Exported fn(): myTestFunction - Ord:0001h

:10001010 8B442410 mov eax, dword ptr [esp+10]

:10001014 56 push esi

:10001015 8B74240C mov esi, dword ptr [esp+0C]

:10001019 0FAF742410 imul esi, dword ptr [esp+10]

:1000101E 85C0 test eax, eax

:10001020 7414 je 10001036

:10001022 8B442418 mov eax, dword ptr [esp+18]

:10001026 8B4C2408 mov ecx, dword ptr [esp+08]

:1000102A 6A63 push 00000000

:1000102C 50 push eax

:1000102D 51 push ecx

:1000102E 6A00 push 00000000

Reference To: USER32MessageBoxA, Ord:01BEh

|

:10001030 FF15B0400010 Call dword ptr [100040B0]

Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:10001020(C)

|

:10001036 8BC6 mov eax, esi

:10001038 5E pop esi

:10001039 C3 ret

-------------------------------------------------------

其中myTestFunction是需要分析的函数,它的里面调用了USER32MessageBoxA

这个函数计算参数个数的时候要注意了,它不是0X18/4的结果,原因是程序入口

的第二条语句又PUSH了一下,PUSH之前的ESP+10就是第4个参数,就是0x10/4 =4

PUSH之后的语句ESP+ XX,

其中(XX-4)/4才对应于第几个参数。

ESP+0C ==第2个参数

ESP+10 ==第3个参数

ESP+18 ==第5个参数

ESP+08 ==第1个参数

----------------------------这样共计算出参数的个数是5个,注意PUSH esi之前与PUSH esi之后,

PUSH一下,ESP的值就减了4,特别需要注意的地方!!!然后看函数的返回处RET指令,

由于看到了RET之前给EAX赋了值,所以可以知道该函数就必定返回了一个值,大家都知道EAX的寄存器

是4个字节的,我们就把它用long来代替好了,现在函数的基本接口已经可以出来了,

long myTestFunction(long p1,long p2,long p3,long p4,long p5);

但是具体的参数类型还需调整,如果该函数里面没有用到任何一个参数的话。那么参数

多少于参数的类型就无所谓了。一般来说这是不太会遇到的。那么,我们怎么去得到该函数的

参数呢?请看下面分析:

你有没有看到 Reference To: USER32MessageBoxA, Ord:01BEh这一条语句,

这说明了,在它的内部使用了WINAPI::MessageBox函数,我们先看一下它的定义:

int MessageBox(

HWND hWnd, // handle of owner window

LPCTSTR lpText, // address of text in message box

LPCTSTR lpCaption, // address of title of message box

UINT uType // style of message box

);

它有4个参数。一般我们知道调用API函数的参数是从右往左压入堆栈的,把它的调用过程

翻译为伪ASM就是:

PUSH uType

PUSH lpCaption

PUSH lpText

PUSH hWnd

CALL MessageBox

---------------------------------------

我们把这个于上面的语句对应一下,就可以清楚的知道

hWnd = NULL(0)

lpText = ecx

lpCaption = eax

uType = MB_OK(0)

---------------------------------

在往上面看,

原来 EAX 中的值是ESP+18中的内容得到了

ECX 中的值是ESP+08中的内容得到了

那么到现在为止就可以知道

lpText = ECX = [ESP+08] ==第1个参数

lpCaption = EAX = [ESP+18] ==第5个参数

现在我们可以把该DLL函数接口进一步写成:

long myTestFunction(LPCTSTR lpText,long p2,long p3,long p4,LPCTSTR lpCaption);

至于第3个参数ESP+10,然后找到该参数使用的地方,imul esi, dword ptr [esp+10]有这么一条指令。

因为imul是乘法指令,我们可以肯定是把ESP+10假设位long是不会错的,同理可以知道第2个参数esp+0C

肯定用long也不会错了,至于第4个参数,它只起到了一个测试的作用,

mov eax, dword ptr [esp+10]

test eax, eax

je 10001036

看到这个参数的用法了吗?

把它翻译位C语言就是:

if(p3)

{

//做je 10001036下面的那些指令

}

return ;

到现在为止可以把第3个参数看成是个指针了吧!就是如果p3为空就直接返回,如果不空就做其它一下事情。

好了,到现在位置可以把正确的接口给列出来了:

long myTestFunction(LPCTSTR lpText,long n1,char pIsNull,long n2,LPCTSTR lpCaption);

//---------------以上内容从http://wwwcsdnnet/expert/topic/636/636873xml整理而来--------------------

下面使用APIHOOK20来分析该参数,相当方便。为了你能更好的理解下面的程序,现举一个MessageBox的例子,

假设本人不知道该函数的参数个数,及参数类型。

首相获取APIHOOK20(网上有的,自己找一下就可以了),解开口,把系统对应的ApiHooksexe,ApiHooksdll

放入系统目录中,或者在PATH中能找到的地方。把ApiHookslib,ApiHooksh放入你的工程中,需要自己建立一个,如:MyApiHook,

类型WIN32 Dynamic-Link Library,(空的),然后添加MyApiHookcpp,该文件中的内容如下:

//--------------------------------MyApiHookcpp文件开始-----------------------------------------

// MyApiHookcpp : Defines the entry point for the DLL application

//功能:把MyApiHookdll注入到testdlgexe的进程中,替换testdlgexe中所调用的DLL中API

//具体使用如下:

//c:\>apihooks -nq MyApiHookdll testdlgexe

//apihooks = apihookexe 和 apihooksdll

// -nq 新打开一个程序(testdlgexe),q不d出信息

//MyApiHookdll = By This File Create

//testdlgexe = 需要替换的程序

#include <stdioh>

#define WIN32_LEAN_AND_MEAN

#include <windowsh>

#include "ApiHooksh"

int (WINAPI pFunction)(long p1,long p2,long p3, long p4);

typedef int (WINAPI Function)(long p1,long p2,long p3, long p4);

int WINAPI MyMessageBoxA(long p1,long p2,long p3, long p4)

{

const nCountParam = 4;

long pp[nCountParam];

pp[0] = p1,pp[1] = p2,pp[2] = p3,pp[3] = p4;

FILE fp = fopen("c:\\1txt","w");

char szBuf[1024];

sprintf(szBuf, "参数内容的列表,很容易判断是否是字符串,或者为NULL\n");

fputs(szBuf, fp);

for(long i = 0; i < nCountParam; i++)

{

sprintf(szBuf,"[pd] = 0x00000000(0)\n",i);

_try {

if(pp)

sprintf(szBuf,"[pd] = 0x08x(d) \t\"s\"\n",i,pp,pp,pp);

}_except(1,1)

{

sprintf(szBuf,"[pd] = 0x08x(d)\n",i,pp,pp);

}

fputs(szBuf,fp);

}

fclose(fp);

return(pFunction(p1, p2, p3,p4));

}

extern "C"__declspec(dllexport) API_HOOK ApiHookChain[2] = {

{"USER32DLL","MessageBoxA",HOOK_EXACT, NULL, NULL, MyMessageBoxA},

{HOOKS_END}

};

BOOL APIENTRY DllMain( HANDLE hModule,DWORD ul_reason_for_call, LPVOID lpReserved)

{

HMODULE hDLL = LoadLibrary("USER32DLL");

if(hDLL)

{

pFunction = (Function )GetProcAddress(hDLL,"MessageBoxA");

FreeLibrary(hDLL);

}

return TRUE;

}

//--------------------------------MyApiHookcpp文件结束-----------------------------------------

上面的这个例子分析了大家都熟悉的MessageBox,假设你不知道该函数的参数,通过上面讲的方法,可以很容易的知道该

函数共有4个参数,有返回数。

于是我们可以把该函数定义为:

int WINAPI MessageBox(long p1,long p2,long p3, long p4);

然后自己定义一个MyMessageBoxA的函数(此函数可以很方便的判断该参数是否为字符串)

int WINAPI MyMessageBoxA(long p1,long p2,long p3, long p4)

通过该函数可以生成的该函数的调用的实际内容,

//------------以下为笔者机器上所得到的信息-----------

参数内容的列表,很容易判断是否是字符串,或者为NULL

[p0] = 0x00000000(0)

[p1] = 0x00416698(4286104) "测试对话框"

[p2] = 0x004166a0(4286112) "信息"

[p3] = 0x00000040(64)

//-------------------------------

根据以上信息,可以很容易的知道第2,3个参数为字符串。然后根据里面的内容可以很容易的知道该参数的实际用途。

因为某需求,需要破解某DLL文件,商业报价3000多,但我自己用的,怎么会付钱呢^^b 对此文件用XXDLL来表示

该DLL组件有使用时间限制,有检查文件是否被修改的限制

以前破解过一些软件和数据库,这次是第一次正式的认真的破解一个商业版软件,抱着必胜DI信心出发发现过程居然很简单或许熟悉软件的话还能简单 @_@

首先对XXDLL文件进行探壳,用PEiD软件,发现是用UPX 0896 - 102 / 105 - 122 DLL -> Markus & Lazlo加壳的。然后尝试用脱壳软件,试了好几个,结果用UPX-iT成功脱壳(这个壳是UPX的变形,很难脱,要碰运气,几次失败,一次成功~:P)

这个DLL文件调用时如果系统时间比截止时间后面,会调用MESSAGEBOXd出"试用期到"的对话框

它对DLL是否被修改的判断方式是读取同文件夹下的XXLIC文件中的信息,和DLL本身CRC()比对之后看看是否有所改变作者说是防止病毒,但我感觉它是为了防止CRACKER如果被修改之后会d出"DLL文件被修改"的错误提示

用的解密跟踪软件是OllyDbg(OllyDbg 109C中文版),记得我2年前用的时候不太会用,但怎么2年后用起来却觉得很顺手@_@

在OllyDbg中我需要找运行到哪一步会d出窗口,但OllyDbg只支持ASCII文本的查找,于是我用ULTRAEDIT打开脱壳后的XXDLL文件,找到前面所述的文字(脱壳后在DLL文件中汉字未加密,嘿嘿),将相关中文字统一在16进制模式的右边栏修改为ACSII码

在OllyDbg中打开调用这个DLL文件的程序AEXE,它会将相关调用DLL库文件读入内存后,按ALT+E(执行模块),可以看到读入哪些DLL文件,然后选中我们的XXDLL文件,按右键选择"跟随入口",就到CPU模式下这个XXDLL文件所在内容窗口SO多的代码,怎么找呢在窗体中按右键选择"搜索"->"字符参考",进可以看到这个DLL里所有能识别的ACSII字符列表哩,很容易就可以看到先前修改的字符串选中字符串后按右键选择"反汇编中跟随"就可以到那一段了

读一下

10002404 898D E4FCFFFF MOV DWORD PTR SS:[EBP-31C],ECX

1000240A 8B95 D6FCFFFF MOV EDX,DWORD PTR SS:[EBP-32A]

10002410 81E2 FFFF0000 AND EDX,0FFFF

10002416 8995 C8FCFFFF MOV DWORD PTR SS:[EBP-338],EDX

1000241C 81BD E4FCFFFF D5>CMP DWORD PTR SS:[EBP-31C],7D5

10002426 75 20 JNZ SHORT SGIP10002441

10002428 83BD C8FCFFFF 09 CMP DWORD PTR SS:[EBP-338],9

1000242F EB 24 JMP SHORT SGIP10002455

10002431 C685 A4F5FFFF 00 MOV BYTE PTR SS:[EBP-A5C],0

10002438 75 1B JNZ SHORT SGIP10002441

1000243A C685 A4F5FFFF 01 MOV BYTE PTR SS:[EBP-A5C],1

10002441 6A 00 PUSH 0

10002443 68 7CC00010 PUSH SGIP1000C07C

10002448 68 84C00010 PUSH SGIP1000C084 ; ASCII "chocobo chocob chocobo chocob chocob chocobo chocob chocobo chocobo chocobo cho"

1000244D 6A 00 PUSH 0

1000244F FF15 44910010 CALL DWORD PTR DS:[<&USER32MessageBoxA>>; USER32MessageBoxA

10002455 B0 01 MOV AL,1

10002457 8BE5 MOV ESP,EBP

10002459 5D POP EBP

1000245A C3 RETN

看到10002426和10002438两段是跳转到d出注册失败的"函数"区域内将其改成其他语句,比如JMP SHORT SGIP10002455,即可运行之后PASS同理修改判断文件是否被修改的部分JMP的 *** 作码为EB

最后一步,就是修改DLL文件了,用ULTRAEDIT打开,查找81 BD E4 FC FF FF ,定好位之后,将原来的75 20 改成EB 20即可,存盘,运行EXE文件调用,PASS,这时已无时间限制,并且不会判断DLL文件是否被修改过哩。

GetProcAddress 函数你只需要传入 dll 函数名字就可以了

不需要传入完整的函数声明,比如:

lpproc = ( TESTDLL ) GetProcAddress( hmod, "Gen2MultiTagIdentify" );

ibrary 即动态链接库文件),是一种不能单独运行的文件,它允许程序共享执行特殊任务所必需的代码和其他资源

比较大的应用程序都由很多模块组成,这些模块分别完成相对独立的功能,它们彼此协作来完成整个软件系统的工作。可能存在一些模块的功能较为通用,在构造其它软件系统时仍会被使用。在构造软件系统时,如果将所有模块的源代码都静态编译到整个应用程序 EXE 文件中,会产生一些问题:一个缺点是增加了应用程序的大小,它会占用更多的磁盘空间,程序运行时也会消耗较大的内存空间,造成系统资源的浪费;另一个缺点是,在编写大的 EXE 程序时,在每次修改重建时都必须调整编译所有源代码,增加了编译过程的复杂性,也不利于阶段性的单元测试。

Windows 系统平台上提供了一种完全不同的较有效的编程和运行环境,你可以将独立的程序模块创建为较小的 DLL 文件,并可对它们单独编译和测试。在运行时,只有当 EXE 程序确实要调用这些 DLL 模块的情况下,系统才会将它们装载到内存空间中。这种方式不仅减少了 EXE 文件的大小和对内存空间的需求,而且使这些 DLL 模块可以同时被多个应用程序使用。Windows 自己就将一些主要的系统功能以 DLL 模块的形式实现。

一般来说,DLL 是一种磁盘文件,以dll、DRV、FON、SYS 和许多以 EXE 为扩展名的系统文件都可以是 DLL。它由全局数据、服务函数和资源组成,在运行时被系统加载到调用进程的虚拟空间中,成为调用进程的一部分。如果与其它 DLL 之间没有冲突,该文件通常映射到进程虚拟空间的同一地址上。DLL 模块中包含各种导出函数,用于向外界提供服务。DLL 可以有自己的数据段,但没有自己的堆栈,使用与调用它的应用程序相同的堆栈模式;一个 DLL 在内存中只有一个实例;DLL 实现了代码封装性;DLL 的编制与具体的编程语言及编译器无关。

在 Win32 环境中,每个进程都复制了自己的读/写全局变量。如果想要与其它进程共享内存,必须使用内存映射文件或者声明一个共享数据段。DLL 模块需要的堆栈内存都是从运行进程的堆栈中分配出来的。Windows 在加载 DLL 模块时将进程函数调用与 DLL 文件的导出函数相匹配。Windows *** 作系统对 DLL 的 *** 作仅仅是把 DLL 映射到需要它的进程的虚拟地址空间里去。DLL 函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有。

调用方式:

1、静态调用方式:由编译系统完成对 DLL 的加载和应用程序结束时 DLL 卸载的编码(如还有其它程序使用该 DLL,则 Windows 对 DLL 的应用记录减1,直到所有相关程序都结束对该 DLL 的使用时才释放它,简单实用,但不够灵活,只能满足一般要求。

隐式的调用:需要把产生动态连接库时产生的 LIB 文件加入到应用程序的工程中,想使用 DLL 中的函数时,只须说明一下。隐式调用不需要调用 LoadLibrary() 和 FreeLibrary()。程序员在建立一个 DLL 文件时,链接程序会自动生成一个与之对应的 LIB 导入文件。该文件包含了每一个 DLL 导出函数的符号名和可选的标识号,但是并不含有实际的代码。LIB 文件作为 DLL 的替代文件被编译到应用程序项目中。

当程序员通过静态链接方式编译生成应用程序时,应用程序中的调用函数与 LIB 文件中导出符号相匹配,这些符号或标识号进入到生成的 EXE 文件中。LIB 文件中也包含了对应的 DL L文件名(但不是完全的路径名),链接程序将其存储在 EXE 文件内部。

当应用程序运行过程中需要加载 DLL 文件时,Windows 根据这些信息发现并加载 DLL,然后通过符号名或标识号实现对 DLL 函数的动态链接。所有被应用程序调用的 DLL 文件都会在应用程序 EXE 文件加载时被加载在到内存中。可执行程序链接到一个包含 DLL 输出函数信息的输入库文件(LIB文件)。 *** 作系统在加载使用可执行程序时加载 DLL。可执行程序直接通过函数名调用 DLL 的输出函数,调用方法和程序内部其 它的函数是一样的。

2、动态调用方式:是由编程者用 API 函数加载和卸载 DLL 来达到调用 DLL 的目的,使用上较复杂,但能更加有效地使用内存,是编制大型应用程序时的重要方式。

显式的调用:

是指在应用程序中用 LoadLibrary 或 MFC 提供的 AfxLoadLibrary 显式的将自己所做的动态连接库调进来,动态连接库的文件名即是上面两个函数的参数,再用 GetProcAddress() 获取想要引入的函数。自此,你就可以象使用如同本应用程序自定义的函数一样来调用此引入函数了。在应用程序退出之前,应该用 FreeLibrary 或 MFC 提供的 AfxFreeLibrary 释放动态连接库。直接调用 Win32 的 LoadLibary 函数,并指定 DLL 的路径作为参数。LoadLibary 返回 HINSTANCE 参数,应用程序在调用 GetProcAddress 函数时使用这一参数。GetProcAddress 函数将符号名或标识号转换为 DLL 内部的地址。程序员可以决定 DLL 文件何时加载或不加载,显式链接在运行时决定加载哪个 DLL 文件。使用 DLL 的程序在使用之前必须加载(LoadLibrary)加载DLL从而得到一个DLL模块的句柄,然后调用 GetProcAddress 函数得到输出函数的指针,在退出之前必须卸载DLL(FreeLibrary)。

正因为DLL 有占用内存小,好编辑等的特点有很多电脑病毒都是DLL格式文件。但不能单独运行。

动态链接库通常都不能直接运行,也不能接收消息。它们是一些独立的文件,其中包含能被可执行程序或其它DLL调用来完成某项工作的函数。只有在其它模块调用动态链接库中的函数时,它才发挥作用。

dll和内存管理

在Win32中,DLL文件按照片段(sections)进行组织。每个片段有它自己的属性,如可写或是只读、可执行(代码)或者不可执行(数据)等等。

DLL代码段通常被使用这个DLL的进程所共享;也就是说它们在物理内存中占据一个地方,并且不会出现在页面文件中。如果代码段所占据的物理内存被收回,它的内容就会被放弃,后面如果需要的话就直接从DLL文件重新加载。

与代码段不同,DLL的数据段通常是私有的;也就是说,每个使用DLL的进程都有自己的DLL数据副本。作为选择,数据段可以设置为共享,允许通过这个共享内存区域进行进程间通信。但是,因为用户权限不能应用到这个共享DLL内存,这将产生一个安全漏洞;也就是一个进程能够破坏共享数据,这将导致其它的共享进程异常。例如,一个使用访客账号的进程将可能通过这种方式破坏其它运行在特权账号的进程。这是在DLL中避免使用共享片段的一个重要原因。

当DLL被如UPX这样一个可执行的packer压缩时,它的所有代码段都标记为可以读写并且是非共享的。可以读写的代码段,类似于私有数据段,是每个进程私有的并且被页面文件备份。这样,压缩DLL将同时增加内存和磁盘空间消耗,所以共享DLL应当避免使用压缩DLL。[1][2]

[3]找到DLL文件地址:C:\WINDOWS\system32\dll时出错(就是你的那个找不到的文件名)

开始--运行--msconfig--启动--找到和你说的类似的选项--取消勾--确定,然后

1,开始-运行-输入:regedit,然后回车

2,选择“我的电脑”,然后点击“文件”-“导出”-随便起个名字点“保存”。这样做的目的是备份一下注册表,以免误 *** 作后及时恢复。恢复的方法是,找到你刚才保存的文件,双击它,然后选择“允许导入”即可。

3,选择“我的电脑”,按F3键,然后输入“”,点击“查找下一个”,找到后一定要核对是不是dll文件,因为你给的文件名不全,如果确认,对该项点“右键”选“删除”。“此时可以输入dll进行查找,结果出来后要看后面的数值部分,不能光看文件名称,只要有dll在的文件不管它边上还写没写别的(如:dll,load),都要删除!”

4,然后再按F3键-删除,直到提示“没有找到相应选项”为止。

5,重新启动计算机,看看系统有没有问题。

注,如果出现了其它严重问题,请恢复注册表。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/12188547.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存