精华内容
下载资源
问答
  • 导入表
    千次阅读
    2018-10-09 10:59:04

    首先说几个基本问题:

    1.导入表的作用是什么?没有它exe能运行么?
    作用:记录了一个exe或者一个dll所用到的其他模块导出的函数;
    所记录的信息有:用了哪些模块(用了哪些dll),用了dll的哪些函数

    2.导出表的作用?没有它exe能运行么?
    作用:记录了导出符号的地址,名称,与序号
    (提示:exe文件中很少有导出表的,大多数dll都有导出表,某些存放资源文件的dll就没有导出表)

    下面截取自笔记,便于理解导入表与导出表的关系
    在这里插入图片描述

    在这里插入图片描述

    3.怎样才能知道一个exe用了哪些API?
    通过遍历导入表就可以知道导入了哪些dll以及dll中的哪些API

    4.已知一个dll名和dll导出函数的名字,如何得到这个函数名的地址
    通过Loadlibrary(GetModelHandle)将dll模块映射进内存并返回一个可以被GetProcAddress函数使用的句柄,再利用GetProcAddress得到dll的加载地址,通过遍历导出表就可以得到该函数的地址.

    5.如何判断导入函数是以序号导入还是以名称导入?
    在IMAGE_THUNK_DATA32这个结构体(结构体里面就是一个联合体,大小为32位)里面,判断结构体字段中的最高位,
    最高位为1:以序号导入
    最高位为0:以名称导入

    6.怎样才能知道导出函数是以序号导出还是以名称导出?
    遍历序号表,判断地址表的下标有没有存在与序号表中,存在就说明是以名称导出,不存在就说明是以序号导出

    双桥结构

    导入表几个简图(笔记中的,将就看吧):

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    解析导入表:

    #include "stdafx.h"
    #include <windows.h>
    
    
    
    DWORD RvaToOffset( IMAGE_NT_HEADERS* pNtHdr , DWORD dwRva ) {
    
        // 1. 找Rva所在的区段
        // 2. 用Rva减去所在区段的首Rva ,再用减出来的差,加上所在
        //    区段的首区段偏移
        IMAGE_SECTION_HEADER* pSechdr = NULL;
        pSechdr = IMAGE_FIRST_SECTION( pNtHdr );
        for( int i = 0 ; i < pNtHdr->FileHeader.NumberOfSections; ++i ) {
            if( dwRva >= pSechdr[ i ].VirtualAddress
                && dwRva <= pSechdr[ i ].VirtualAddress + pSechdr[ i ].SizeOfRawData ) {
    
                dwRva -= pSechdr[ i ].VirtualAddress;
                dwRva += pSechdr[ i ].PointerToRawData;
                return dwRva;
            }
        }
        return -1;
    }
    
    
    
    int main( ) {
        
        //typedef struct _IMAGE_IMPORT_DESCRIPTOR {
        //  union {
        //      DWORD   Characteristics;            
        //      DWORD   OriginalFirstThunk; /*保存导入函数名称表(INT)的地址(RVA)*/        
        //  } DUMMYUNIONNAME;
        //  DWORD   TimeDateStamp;
        //  DWORD   ForwarderChain;// 是否是dll转发
        //  DWORD   Name;/*导入的模块名(DLL的名字)*/
        //  DWORD   FirstThunk;/*导入函数地址表(IAT)(RVA)*/
        //} IMAGE_IMPORT_DESCRIPTOR;
        // 解析导入表
        // 1. 读取文件到内存
        printf( "请输入要解析的DLL的路径:" );
        char szPath[ MAX_PATH ];
        gets_s( szPath , MAX_PATH );
    
        HANDLE hFile = INVALID_HANDLE_VALUE;
        hFile = CreateFileA( szPath , GENERIC_READ , FILE_SHARE_READ ,
                             NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL );
        if( hFile == INVALID_HANDLE_VALUE ) {
            printf( "文件不存在\n" );
            system( "pause" );
            return 0;
        }
        DWORD dwHeight = 0;
        DWORD dwFileSize = GetFileSize( hFile , &dwHeight );
    
        BYTE* pBuff = new BYTE[ dwFileSize ];
    
        ReadFile( hFile , pBuff , dwFileSize , &dwFileSize , NULL );
    
        // 2. 解析出Dos头,Nt头,扩展头
        IMAGE_DOS_HEADER* pDosHdr = NULL;
        IMAGE_NT_HEADERS* pNtHdr = NULL;
        IMAGE_OPTIONAL_HEADER* pOptHdr = NULL;
        IMAGE_DATA_DIRECTORY* pDataDir = NULL;
        IMAGE_EXPORT_DIRECTORY* pExortTable = NULL;
    
    
        pDosHdr = (IMAGE_DOS_HEADER*)pBuff;
        pNtHdr = (IMAGE_NT_HEADERS*)( (ULONG_PTR)pDosHdr + pDosHdr->e_lfanew );
        pOptHdr = &pNtHdr->OptionalHeader;
    
        // 3. 得到扩展头中的数据目录表
        pDataDir = pOptHdr->DataDirectory;
    
        // 4. 通过数据目录表中的第1个元素得到导入表的RVA
        DWORD dwImpRva = pDataDir[ 1 ].VirtualAddress;
        if( dwImpRva == 0 ) {
            printf( "没有导入表" );
            system( "pause" );
            return 0;
        }
        // 5. 将导入表的RVA转换成文件偏移
        DWORD dwImpOfs = RvaToOffset( pNtHdr , dwImpRva );
    
        // 6. 使用导入表结构体指针指向导入表所在的内存地址
        IMAGE_IMPORT_DESCRIPTOR* pImpTab = NULL;
        pImpTab = (IMAGE_IMPORT_DESCRIPTOR*)( dwImpOfs + (ULONG_PTR)pDosHdr );
    
        // 7. 遍历所有的导入表
        //    导入表是以一个全0元素作为结束的标志
        while( pImpTab->Name != 0 ) {
    
            // 7.1 获取这个导入所导入的DLL的名称,导入表里面的Name也是一个RVA
            ULONG_PTR dwNameOfs = RvaToOffset( pNtHdr , pImpTab->Name );
            char* pName = nullptr;
            pName = (char *)( dwNameOfs + (ULONG_PTR)pDosHdr );
            printf( "导入的DLL:%s\n" , pName );
            //IMAGE_THUNK_DATA32
            // 7.2 遍历从这个dll导入的函数名称
            DWORD dwINToffset = RvaToOffset(pNtHdr, pImpTab->OriginalFirstThunk);
    
            // INT : 导入名称表
            // 这个表记录了所有导入函数名称的地址(RVA)
            // 每个地址都是4/8字节(如果是32位PE文件,就是4字节,如果是64位的PE文件就是8字节)
            ULONG_PTR* pInt = (ULONG_PTR*)( dwINToffset + (ULONG_PTR)pDosHdr );
    
            while( *pInt != 0 ) {
                // 导入函数有两种方式:
                // 1. 以序号导入
                // 2. 以名称导入
                // 如果INT表中保存的值,最高位是0的时候,说明这个值是一个函数名称的RVA
                // 否则这个值的低16位就是一个导入的序号。
                if( IMAGE_SNAP_BY_ORDINAL( *pInt ) ) {
    
                    // 以序号方式导入
                    // 以序号方式导入, 保存的是序号,需要只有2字节
                    printf( "\t0x%04X\n" , *pInt & 0xFFFF );
                }
                else {
                    // 以名称方式导入,数组保存的RVA,并非是一个字符串的RVA
                    // 而是一个结构体(IMAGE_IMPORT_BY_NAME)的RVA
                    IMAGE_IMPORT_BY_NAME* pImpByName = NULL;
                    DWORD dwNameRva = *pInt;
                    dwNameOfs = RvaToOffset( pNtHdr , dwNameRva );
                    pImpByName = (IMAGE_IMPORT_BY_NAME*)( dwNameOfs + (ULONG_PTR)pDosHdr );
                    printf( "\t序号:%04X,名称:%s这是以名称方式导入的\n" ,
                            pImpByName->Hint ,
                            pImpByName->Name );
                }
    
                // 得到下一个导入函数的名称的地址
                ++pInt;
            }
            // 得到下一个导入表的地址
            ++pImpTab;
        }  
    
        system( "pause" );
        return 0;
    }
    
    

    另外一种方式:

    遍历导入表中的INT修复IAT
    while (exeimport->Name != NULL) //遍历模块
    {
    HMODULE h_dllModule = apis.pfnLoadLibraryA((char *)(exeimport->Name + ImageBase));
    PIMAGE_THUNK_DATA  import_Int = (PIMAGE_THUNK_DATA)(exeimport->OriginalFirstThunk+ImageBase);
    PIMAGE_THUNK_DATA  import_IAT = (PIMAGE_THUNK_DATA )(exeimport->FirstThunk+ ImageBase);
    
    while (import_Int->u1.Ordinal != 0) //遍历函数
    {
    UCHAR *buf = (UCHAR *)apis.pfnHeapAlloc(heap, HEAP_ZERO_MEMORY, 10);
    buf[0] = 0xb8;
    buf[5] = 0xff;
    buf[6] = 0xe0;
    //new char[20]{ "\xB8\x00\x00\x00\0x00\0xff\0xe0" };
    DWORD opl = 0;
    apis.pfnVirtualProtect((LPVOID)buf, 20, PAGE_EXECUTE_READWRITE, &opl);
    if (import_Int->u1.Ordinal &0x80000000) //这里是重点!!!序号导出, 最高位为1,这里是获取最高位,如果最高位为1,就执行下面里面的语句,即
    //以序号导入 ,否则以名称导入,执行else中的语句
    {
    
    
    //获取序号函数
    LPVOID apiaddr =
    apis.pfnGetProcAddress(h_dllModule, (char *)(import_Int->u1.Ordinal & 0xFFFF));
    
    *(DWORD*)&buf[1] = (DWORD)apiaddr;  //函数写入shellcode
    
    //DWORD funaddr = ;
    
    
    apis.pfnVirtualProtect((LPVOID)(import_IAT ), 4, PAGE_EXECUTE_READWRITE, &opl);
    *(DWORD*)((DWORD)import_IAT ) = (DWORD)buf; //将函数写入到iat
    }
    else
    {
    //DWORD Faddr = *(DWORD*)(import_Int->u1.AddressOfData + ImageBase);
    PIMAGE_IMPORT_BY_NAME funname = (PIMAGE_IMPORT_BY_NAME)(import_Int->u1.AddressOfData+ImageBase);
    LPVOID apiaddr =
    apis.pfnGetProcAddress(h_dllModule, funname->Name);
    
    *(DWORD*)&buf[1] = (DWORD)apiaddr;  //函数写入shellcode
    
    apis.pfnVirtualProtect((LPVOID)(import_IAT), 4, PAGE_EXECUTE_READWRITE, &opl);
    *(DWORD*)((DWORD)import_IAT ) = (DWORD)buf; //将函数写入到iat
    //              DWORD funaddr =import_IAT->u1.Function  ;  //获取iat地址
    //
    //              apis.pfnVirtualProtect((LPVOID)funaddr, 4, PAGE_EXECUTE_READWRITE, &opl);
    //              *(DWORD*)(funaddr) = (DWORD)buf; //将函数写入到iat
    }
    
    import_Int++;
    import_IAT++;
    
    }
    exeimport++;
    }
    
    
    
    

    导入表:

    (exe例子为:内存管理-VirtualAlloc)
    LordPE查看其导入表RVA:

    在这里插入图片描述
    010editor中验证:
    在这里插入图片描述

    导入表位置,落在了.idata段:
    在这里插入图片描述

    1A000 【7800】
    1A1C8 【79C8】

    79C8:(这个值为文件中的偏移,就是它在文件中的起始位置,利用79C8在010editor里面可以找到导入表)
    在010editor中:

    在这里插入图片描述

    typedef struct _IMAGE_IMPORT_DESCRIPTOR{
    union {
    DWORD Characteristics;
    DWORD OriginalFirstThunk;//指向一个结构体数组的相对位移,RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    }DUMMYUNIONNAME;
    DWORD TimeDataStamp;
    DWORD ForwarderChain;
    DWORD Name;    //导入的PE文件的名字的相对位移(RVA)
    DWORD FirstThunk ;//指向一个结构体数组的相对位移(RVA  to IAT)
    }
    

    在这里插入图片描述

    18 A2 01 00【OriginalFirstThunk:INT(Import Name Table)导入名称表地址RVA】
    00 00 00 00
    00 00 00 00
    22 A4 01 00【DLL名称的RVA】
    00 A0 01 00【IAT(Import Address Table)导入地址表地址RVA】

    1.dll的名字【22 A4 01 00(小端)—>0001A422(因为1A000对应7800,故这里dll在文件中偏移为7C22)】
    在这里插入图片描述

    2.看下INT(OriginalFirstThunk):1A218【7A18】(以全0结尾)

    在这里插入图片描述

    函数名数组(对应IMAGE_THUNK_DATA32结构体数组,每一个结构体就是一个联合体)

    E0 A3 01 00----0001A3E0【7BE0】最高位为0,说明是以名称导入的,不是序号导入的;
    一共导入了25个函数,这里只写一个,其他依次类推!
    注意:IAT和INT都指向下面的这个数据结构,4Byte

    typedef struct  _IMAGE_THUNK_DATA32{
    union{
    DWORD ForwarderString;
    DWORD Function;//导入函数的地址,在加载到内存之后,这里才起作用
    DWORD Ordinal;//假如是序号导入的,会用到这里
    DWORD AddressOfData;//假如是函数名导入,会用到这里,它指向另外一个结构体PIMAGE_IMPORT_BY_NAME
    }u1;
    }IMAGE_THUNK_DATA32;
    //如果是函数名导入的,AddressOfData会指向下面这个结构体
    typedef struct _IMAGE_IMPORT_BY_NAME{
    WORD  Hint;//序号
    CHAR Name[1];//不定长,字符串
    
    }
    

    由上可知:是按照函数名导入的(大多数都是按名称导入的),故上面的地址值,就会指向一个PIMAGE_IMPORT_BY_NAME的结构体
    【7BE0】
    在这里插入图片描述

    在这里插入图片描述

    看下IAT(00 A0 01 00->0001A000–>【7800】)

    在这里插入图片描述

    发现最高位也都是0,所以,也是名称导入的,另外,还可以发现,这个位置的值,和INT的值是一样的,因此,不再赘述了
    这里的kernel32.dll里面有25个函数

    在这里插入图片描述

    更多相关内容
  • PE结构&导入表

    千次阅读 2021-02-02 21:43:55
    导入表简介 当我们源文件里面需要去如何画窗口,如何显示指定字符串这样功能的代码,只需要简单调用Windows API函数。这些调用的函数在源文件中并不存在。这些代码存储在DLL文件中,即动态链接库中。在动态链接库里...

    PE体系

    PE结构&整体叙述

    PE结构&导入表

    PE结构&导出表

    PE结构&基址重定位表

    PE结构&绑定导入实现

    PE结构&延迟加载导入表

    导入表简介

    当我们源文件里面需要去如何画窗口,如何显示指定字符串这样功能的代码,只需要简单调用Windows API函数。这些调用的函数在源文件中并不存在。这些代码存储在DLL文件中,即动态链接库中。在动态链接库里存放的不是函数的源代码,而是编译链接后生成的字节码。
    源程序调用了动态链接库的相关函数,在进行编译和链接的时候,编译程序和链接程序就会把调用的相关信息写入最终生成的PE文件中,从而来告诉操作系统这些函数的执行字节码能从哪里获取,这些信息就是导入表所要描述的内容

    DLL加载方式有两种:显式链接(Explicit Linking) 和 隐式链接(Implicit Linking)

    1. 显示链接:程序在使用DLL时进行加载,使用完毕后释放内存
    2. 隐式链接:程序在开始时即一同加载DLL,程序终止时再释放占用的内存

    IAT提供的机制与DLL的隐式链接有关。

    优点:

    1. 不把函数库包含进应用程序中,单独组成DLL文件,在需要使用时再进行调用。
    2. 使用内存映射技术将加载后的DLL代码、资源在多个进程中实现共享。
    3. 在对函数库进行更新时,只更新DLL文件即可。

    导入函数

    当我们调用一个API时,这个API我们不可能自己手写,基础源码这些东西都不知道,所以直接导入头文件然后使用即可。

    #include<iostream>
    #include<Windows.h>
    using namespace std;
    int main() {
    	LPCSTR text = "hello world";
    	LPCSTR title = "第一个MessageBoxA";
    	MessageBoxA(NULL, text, title, MB_OK);
    
    }
    

    关于API调用的汇编代码如下:

    .text:00401516 mov     [ebp+text], offset aHelloWorld ; "hello world"
    .text:0040151D mov     [ebp+title], offset unk_48800C
    .text:00401524 mov     dword ptr [esp+0Ch], 0 ; uType
    .text:0040152C mov     eax, [ebp+title]
    .text:0040152F mov     [esp+8], eax    ; lpCaption
    .text:00401533 mov     eax, [ebp+text]
    .text:00401536 mov     [esp+4], eax    ; lpText
    .text:0040153A mov     dword ptr [esp], 0 ; hWnd
    .text:00401541 mov     eax, ds:__imp__MessageBoxA@16 ; MessageBoxA(x,x,x,x)
    .text:00401546 call    eax ; MessageBoxA(x,x,x,x) ; MessageBoxA(x,x,
    

    关于导入函数就两行:

    .text:00401541 mov     eax, ds:__imp__MessageBoxA@16 ; MessageBoxA(x,x,x,x)
    .text:00401546 call    eax ; MessageBoxA(x,x,x,x) ; MessageBoxA(x,x,
    

    也就是把一个内存单元里面存的地址放在eax里面去,然后call它。即MessageBoxA的实际地址被放在一个偏移处,查看这个偏移
    在这里插入图片描述
    地址0x004924C0存放着0x77211930MessageBoxA的实际地址)
    0x004924C0内存单元开始取dd长度的内存数据放在eax里面,
    然后直接 call 0x77211930

    查看一下文件中0x004924C0中存放的数据:
    在这里插入图片描述
    它存放的是0x61562100

    查看一下内存中0x004924C0中存放的数据:
    在这里插入图片描述
    它存放的是0x77211930
    这意味着,文件被装载到内存后,这里的值发生了变化,真正的API函数地址的应该是内存中此处的值。那文件中的值0x61562100和内存映像中的值0x77211930它俩有什么关系呢?

    注意

    dump程序时,

    错误示范:

    在这里插入图片描述
    这样操作后,你得到的文件是一个在这里插入图片描述

    dmp文件,然后我找了三个小时。。啥也没找到。。。

    正确示范:

    在这里插入图片描述
    这样dump后你得到的才是一个exe程序
    在这里插入图片描述
    文件偏移和虚拟地址转换才用得上。。。以前dump的时候都是直接用的是PEtools,今晚不知道脑子哪里抽筋,偏偏乱搞了三小时。。。

    观察一下文件数据,导入表中数据
    在这里插入图片描述
    RVA数值为0x92000,大小为0xEE8

    核心内容

    在这里插入图片描述
    导入表数据所在地址RVA=0x92000
    导入表数据大小=0xEE8
    导入函数数据地址表所在地址RVA=0x9228C
    导入地址表表数据大小=0x23C
    在这里插入图片描述
    转换成文件偏移后是:
    导入表数据所在地址0x8F200,导入表数据大小=0xEE8
    导入地址表数据所在地址0x8F48C,导入地址表表数据大小=0x23C

    导入表描述符IMAGE_IMPORT_DESCRIPTOR

    导入表数据的起始是一组导入表描述符结构。每组为20个字节,该结构定义如下:

    IMAGE_IMPORT_DESCRIPTOR	STRUCT
    union
    	Characteristics					dd
    	OriginalFirstThunk				dd	;000h	-1
    ends	
    TimeDateStamp						dd	;0004h	-	时间表
    ForwarderChain						dd	;0008h	-	链表的前一个结构
    Name1								dd	;000ch	-	指向链接库名字的指针
    FirstThunk							dd	;0010	-2
    

    以下作出解释:

    IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk:

    +0000h,双字。因为它是指向另外数据结构的通路,因此简称桥1。该字段指向一个包含了一系列结构的数据。
    指向的数组中每个结构定义了一个导入函数的信息,最后一个内容为全0的结构作为结束。指向的数据中每一项为一个结构,此结构的名称是IMAGE_THUNK_DATA。该结构实际上只是一个双字,但在不同时刻却拥有不同的解释。该字段有两种解释:

    1. 双字最高位为0,表示导入符号是一个数值,该数值是一个RVA。
    2. 双字最高位为1,表示导入符号是一个名称

    IMAGE_IMPORT_DESCRIPTOR.TimeDateStamp:

    +0004h,双字。时间戳,一般不用。如果该导入表被绑定,那么绑定后的这个时间戳就被设置为对应DLL文件的时间戳。操作系统在加载时,可以通过这个时间戳来判断绑定的信息是否过时

    IMAGE_IMPORT_DESCRIPTOR.ForwarderChain:

    +0008h,双字。链表的前一个结构

    IMAGE_IMPORT_DESCRIPTOR.Name1:

    +000ch,双字。这个字段的含义和名称并不一致,这里的Name1是一个RVA,它指向该结构对应的DLL文件的名称,而这个名称是以“\0”结尾的Ansi字符串。

    IMAGE_IMPORT_DESCRIPTOR.FirstThunk :

    +0010h,双字。与OriginalFirstThunk相同,它指向的链表定义了针对Name1这个动态链接库引入的所有导入函数,简称桥2

    导入表双桥结构

    重新找个程序举例,上面那个数据太大了,头疼。。。
    在这里插入图片描述

    在这里插入图片描述
    导入表数据所在地址RVA=0x1B1C4
    导入表数据大小=0x50
    导入函数数据地址表所在地址RVA=0x1B000
    导入地址表表数据大小=0x1C4

    转换成文件偏移后是:

    导入表数据所在地址0x83C4,导入表数据大小=0x50
    导入地址表数据所在地址0x8200,导入地址表表数据大小=0x1C4
    在这里插入图片描述

    在这里插入图片描述

    桥1和桥2最终都通向了一个目的地,都指向了引入函数的“编号-名称”(Hint/Name)描述部分。而从桥2到目的地的过程中,还经过了另外一个很重要的结构IAT(Import Address Table)
    在这里插入图片描述

    AC B2 01 00
    

    桥1,最高位为0,这是一个RVA,表明函数是以字符串类型的函数名导入的。RVA转换为FOA,值为
    0x84AC,从文件的该位置开始取双字,直到取出的双字为"0"结束,每一个双字都是结构IMAGE_THUNK_DATA。该结构的详细定义如下

    
    IMAGE_THUNK_DATA STRUCT
    	union	u1
    		ForwarderString		dd?
    		Function			dd?
    		Ordinal				dd?
    		AddressOfData		dd?
    	ends
    IMAGE_THUNK_DATA	ENDS
    

    在这里插入图片描述

    0x0001B450转换成文件偏移为0x8650
    在这里插入图片描述

    2E	00	5F	5F	76	63	72	74	5F	47	65	74	4D	6F	64	75	6C	65	46	69	6C	65	4E	61	6D	65	57	00
    

    这些值组成的数据结构就是IMAGE_IMPORT_BY_NAME

    IMAGE_IMPORT_BY_NAME STRUCT
    	Hint	dw	?;0000h	-函数编号
    	Name1	db	?;0004h	-表示函数名的字符串
    	IMAGE_IMPORT_BY_NAME ENDS
    

    以下是对每个字段的具体解释:

    IMAGE_IMPORT_BY_NAME.Hint:
    +0000h,双字。函数的编号,在DLL中对每个函数进行了编号,访问函数时可以通过名称访问,也可以通过编号访问

    IMAGE_IMPORT_BY_NAME.Name1:
    +0004h,大小不确定。函数名字字符串的具体内容,以“\0”作为字符串结束标志。
    其中002E标识该函数在动态链接库的编号,后面紧跟着函数名“GetModuleFileNameW”。

    00 00 00 00
    

    时间戳,这里为0

    00 00 00 00
    

    链表的前一个结构,这里为0

    9E	B4	01	00
    

    RVA,指向动态链接库RUNTIME140D.dll的名字字符串,转换为文件偏移是0x869E
    在这里插入图片描述

    98	B0	01	00
    

    桥二,转换成文件偏移是0x8298
    在这里插入图片描述
    在这里插入图片描述

    根据上面可知IAT0x8200~0x83C4,桥2指向的地方在IAT范围内,所以指向IAT
    在这里插入图片描述
    和桥1指向的数据值相同。。但是存储的位置是不同的。桥1指向的INT与桥2指向的IAT内容完全一样,但INT和IAT却存储在文件的不同位置。

    每一个结构IMAGE_IMPORT_DESCRIPORT都对应一个唯一的动态链接库,以及引用了该动态链接库的多个函数,每个函数的最终“值-名称”描述均可以沿桥1或者桥2找到。这种导入表结构被称为双外结构。
    双桥结构的导入表在文件中存在两份内容完全相同的地址列表。一般情况下,桥2指向的地址列表被定义为IAT,而桥1指向的地址列表则被定义为INT(import name table)。

    注意:
    有的链接程序只只为导入表存储一个桥,如Borland公司的Tlink只保留桥2,这样的导入表我们称之为单桥结构的导入表(单桥结构的导入表是无法指向绑定导入操作的。)

    文件中的导入表:

    在这里插入图片描述

    在文件中,桥1指向INT,桥2指向IAT,内容一致。
    在这里插入图片描述

    内存中的导入表:

    在这里插入图片描述
    在内存中,桥1可以找到调用的函数名称或函数的索引编号,桥2却可以帮你找到该函数指令代码在内存空间中的地址。
    当PE被加载进虚拟地址空间以后,IAT 的内容会被操作系统更改为函数的VA。这个修改最终会导致通向“值-名称”描述的桥2发生断裂,如上图。

    当桥2发送断裂以后,如果没有桥1作为参照(因为桥1和桥2维护了两个一一对应的函数RVA),我们就无法重新找到该地址到底是调用了那个函数。这就是为什么会存在两个桥的原因。也是为什么单桥导入表无法实施绑定的原因。

    实际操作

    内存中的导入表:
    在这里插入图片描述
    桥1的值为01B2AC
    在这里插入图片描述

    桥2的IAT 值为0x01B098
    在这里插入图片描述

    两个函数实际地址值和函数名(函数编号)可以一一对应。。。

    PE装载器把导入函数输入至IAT的顺序

    1. 读取IID的Name成员,获取库名称字符串(eg:kernel32.dll)
    2. 装载相应库:
      LoadLibrary(“kernel32.dll”)
    3. 读取IID的OriginalFirstThunk成员,获取INT地址
    4. 逐一读取INT中数组的值,获取相应IMAGE_IMPORT_BY_NAME地址(RVA)
    5. 使用IMAGE_IMPORT_BY_NAME的Hint(ordinal)或Name项,获取相应函数的起始地址:GetProcAddress(“GetCurrentThreadld”)
    6. 读取IID的FirstThunk(IAT)成员,获得IAT地址
    7. 将上面获得的函数地址输入相应IAT数组值
    8. 重复以上步骤4~7,知道INT结束(遇到NULL)

    同一个DLL文件的多个函数的导入表

    在这里插入图片描述
    这是文件中的导入表,上图中FirstThunk和OriganalFirstThunk一样也有一份函数指针表,即桥2.只是没画而已下面是装载入内存后的导入表:
    在这里插入图片描述
    定位导入函数地址表的方法有两种:

    1. 从导入表的而最后一个导入表项## IMAGE_IMPORT_DESCRIPTOR结构中的字段IMAGE_IMPORT_DESCRIPTOR.FirstThunk定位IAT
    2. 通过数据目录第13个数据项的描述直接定位IAT

    每个动态链接库都维护了自己的IAT内容,不同的 链接库维护的这些内容可以是不连续的。

    导入表的平面解析
    在这里插入图片描述
    解释如下:
    在这里插入图片描述

    展开全文
  • PE文件——导入表&导出表&函数覆盖

    千次阅读 2022-04-06 00:47:51
    第一个字段4D 5A被定义成字符“MZ”作为识别标志,后面的一些字段指明了入口地址、堆栈位置和重定位位置等。 对于PE文件来说,有用的是最后的e_lfanew字段,这个字段指出了真正的PE文件头在文件中的位置,这个位置...

    PE文件的基本结构图

    在这里插入图片描述

    • 第一个字段4D 5A被定义成字符“MZ”作为识别标志,后面的一些字段指明了入口地址、堆栈位置和重定位表位置等。
    • 对于PE文件来说,有用的是最后的e_lfanew字段,这个字段指出了真正的PE文件头在文件中的位置,这个位置总是以8字节为单位对齐的。
      在这里插入图片描述

    判断是否是PE文件

    1.使用Winhex工具,从文件头4D 5A(MZ)开始,跳转3C(即偏移3C);
    2.跳转后可读取到数据为0000 00B0;
    3.再跳转到地址0000 00B0;
    4.若该地址数据为50 45(即PE)就为PE文件。
    在这里插入图片描述

    导入表

    导入表结构:

    typedef struct _IMAGE_IMPORT_DESCRIPTOR {
        union {
            DWORD   Characteristics;            
            DWORD   OriginalFirstThunk; // 指向 导入名称表INT(ImportNameTable)的RVA
        } DUMMYUNIONNAME;
        DWORD   TimeDateStamp;                  
        DWORD   ForwarderChain;                 
        DWORD   Name;                   // 指向 DLL名称的地址 RVA
        DWORD   FirstThunk;             // 指向 导入地址表IAT(ImportAddressTable)的RVA
    } IMAGE_IMPORT_DESCRIPTOR;
    typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
    

    导入表&桥1&桥2位置

    注意!WinHex右往左读
    如:在这里插入图片描述
    读值:2084
    使用软件:PEditor、WinHex
    1.WinHex打开,PE头偏移80H得到导入表的RVA。
    2.根据节表(可用PEditor查看),将RVA转成FOA,WinHex跳转该FOA得到一串20个字节描述的一个dll文件,如下图蓝色部分。
    FOA=(RVA-Virtual Offset)+Raw Offset
    在这里插入图片描述
    节表结构
    如:
    在这里插入图片描述

    3.第一个字节为桥1的RVA,计算其FOA并跳转得到桥1的数组,每四个字节为一组,到四个字节均为00结束。每一组的FOA跳转得到对应函数。
    4.第四个字节,计算其FOA跳转得到winresult.dd.
    5.第五个字节为桥2RVA,计算其FOA并跳转得到静态指向桥2的数组。
    注意!桥2动态和静态指向数组不一样
    动态时桥2组数里是user32.dll的函数地址,所以指向桥2的地址会是

    导出表

    导出表结构:

    typedef struct _IMAGE_EXPORT_DIRECTORY {
        DWORD   Characteristics;
        DWORD   TimeDateStamp;
        WORD    MajorVersion;
        WORD    MinorVersion;
        DWORD   Name;
        DWORD   Base;
        DWORD   NumberOfFunctions;
        DWORD   NumberOfNames;
        DWORD   AddressOfFunctions;     // RVA from base of image
        DWORD   AddressOfNames;         // RVA from base of image
        DWORD   AddressOfNameOrdinals;  // RVA from base of image
    } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
    

    导出表位置

    软件:WinHex
    1.PE偏移78H,得到导出表RVA。
    2.根据节表将RVA转成FOA,并跳转该FOA。
    3.从这开始对应导出表的数据结构写出对应名称的数值。
    其中Address of Functions要计算FOA,跳转得到该值为第一个导出函数RVA,依次往下分别为其余三个函数地址的RVA值,再转FOA跳转得到函数名。
    Address of NameOrdinal与Address of Functions方式相同。

    实现两种方式的导出函数覆盖

    达到.exe以动画打开效果

    (修改导出结构中函数入口地址)
    1.先找到两个函数FadeInOpen和AnimatOpen的入口地址;
    2.将两个地址进行交换(exe文件想要调用FadeInOpen时实际是调用了AnimateOpen)

    使.exe运行会弹出messagebox

    (覆盖fadeinopen函数的指令代码)
    1.在winhex找到fadeinopen的地址从那里开始修改
    2.保存原始栈基地址
    3.维持栈平衡的返回命令
    4.到OD单步执行user32.messageboxA看缓冲区的地址,将其地址覆盖到该函数最好四个字节。

    练习题

    1.某变量的FOA为410H,试分析其位于哪一节(给出分析过程。)?该变量的RVA为多少(给出计算过程)?
    在这里插入图片描述由节表可知,.text的起始为00000400,大小为00000200;所以变量的FOA为410H属于.text节;
    因为400<410<600
    RVA = (410-400)+1000=1100H
    2.查阅资料,简述病毒获取Kernel32模块基地址的重要性
    答:获取了kernel32.dll基址后就可以获取LoadLibrary()和GetProcAddress()的地址,有了它们之后我们就不用大费周章的去找API了。使用Kernel32.DLL中的LoadLibrary 和GetProcAddress 两个API可以获取任意DLL中导出的任意函数在进程空间中的位置即可进行入侵。
    3.利用PEditor打开firstwindow.exe,分析该PE的导入表。该PE文件描述导入表的数据目录项的偏移是多少?导入表的VA和大小分别是多少?该EXE用到多少个DLL文件。验证与PEditor中查看到的是否一致?
    在这里插入图片描述
    在这里插入图片描述

    导入表的数据目录项的偏移是:80H;
    导入表的VA和大小分别是:00402084(RVA是2084;基址是00400000;VA=RVA+基址),大小FOA=RVA-virtual offest+Raw offest=684;跳到FOA(文件偏移处)可以看见;
    该EXE用到3个DLL文件,因为在winhex打开找到导入表对应数组时连续3个20个字节才到全为0的20字节。
    在这里插入图片描述
    对比PEditor:一致!
    4.利用Winhex查看Winresult.DLL 并分析其提供函数的名字及对应入口地址。画出导出表结构图(类似图2)
    在这里插入图片描述
    分析:
    在这里插入图片描述
    导出表:
    RVA:00002140,Vitual Offset:00002000,Raw Offset:800
    因此FOA:940,跳到地址940既是导出表的地址:
    在这里插入图片描述
    标志:00000000
    时间日期记录:4D510EEE
    Dll的首版本号:0000
    Dll的次版本号:0000
    Dll的模块名(RVA):00002190,FOA:990,跳转可得文件名为winresult.dll
    在这里插入图片描述
    基数:00000010
    函数的总数:00000004
    有名函数的总数:00000004
    FAT表RVA值(AddressOfFunctions):00002168 FOA(968),跳转的得到968地址值为00001183
    在这里插入图片描述
    该值为第一个导出函数RVA,依次往下分别为其余三个函数地址的RVA值:00001022、00001282、00001323
    在这里插入图片描述

    与Peditor查看到的一致:
    在这里插入图片描述
    FAT表RVA值(AddressOfNames):00002178 FOA:(978)
    跳转到978地址得到地址为0000219E
    第一个导出函数RVA值:0000219E,FOA=99E
    第二个导出函数RVA值:000021AB,FOA=9AB
    第三个导出函数RVA值:000021B7,FOA=9B7
    第四个导出函数RVA值:000021C2,FOA=9C2
    查看对应文件偏移量处的函数名:
    在这里插入图片描述
    5.pedtior打开本机的kernel32.DLL,其导出表RVA?导出表大小?找到无导入表情况下需要的两个函数的名称及其入口地址。 (本机的kernel32.DLL用winhex存到桌面)
    在这里插入图片描述
    导出表RVA:00092D30导出表大小:0000DC14
    在得到kernel32.dll的基地址后,就可以获得LoadLibray()函数来继续加载其他的动态链接库,再通过GetProcAdress()函数来获得相应需要的api函数地址,这样也就做到了可移植性的要求。
    LoadLibray:
    在这里插入图片描述
    GetProcAddress:
    在这里插入图片描述
    6.实现两种方式的导出函数覆盖-1
    修改winResult.dll导出结构中的函数入口地址,达到firstwindow.EXE以动画方式打开的效果。描述你所做的工作。
    1.先找到两个函数FadeInOpen和AnimateOpen的入口地址:00001022和0001282
    在这里插入图片描述
    2.将两个地址进行交换(exe文件想要调用FadeInOpen时实际是调用了AnimateOpen)
    在这里插入图片描述

    7.实现两种方式的导出函数覆盖-2 (P166)
    覆盖fadeinopen函数的指令代码:使得运行firstwindow.EXE程序时会弹出messagebox(OD打开看地址)。如下图所示:
    1.Winhex打开winResult.dll,修改函数FadeInOpen(文件起始偏移0x0682)定义部分:保存原始栈基地址、维持栈平衡的返回命令:
    原始得:
    在这里插入图片描述
    修改后:
    在这里插入图片描述
    在这里插入图片描述

    红框部分是messageboxA在user32.dll的地址,可以通过OD打开其他导入了messageboxA的文件查看其所在的地址,例如上次作业的Helloworld.exe,注意在Winhex上使用小端方式!
    运行:
    在这里插入图片描述

    以上是学习PE文件的一些笔记,欢迎大家查阅指正~

    展开全文
  • 导入表定位以及解析(手动FileBuffer) 导入表定位以及解析(手动ImageBuffer) 代码定位导入表并打印其数据 导入表注入 导入表是PE数据组织中的一个很重要的组成部分,它是为实现代码重用而设置的.通过分析导入表...

    目录

    导入表定位以及解析(手动FileBuffer)

    导入表定位以及解析(手动ImageBuffer)

    代码定位导入表并打印其数据


    导入表是PE数据组织中的一个很重要的组成部分,它是为实现代码重用而设置的.通过分析导入表数据,可以获得诸如PE文件的指令中调用了多少外来的函数,以及这些外来函数都存在于哪些动态链接库里等信息.

    Windows加载器在运行PE时会将导入表中声明的动态链接库一并加载到进程的地址空间,并修正指令代码中调用的函数地址.

    在数据目录项中一共有四种类型的数据与导入表有关(导入表、导入函数地址表、绑定导入表、延迟加载导入表).

    导入数据所在的节通常被命名为.idata,它包含了PE映像中所有导入的符号.导入信息在EXE和DLL中几乎都存在.

    导入表定位以及解析(手动FileBuffer)

    IMAGE_IMPORT_DESCRIPTOR

    结构及成员含义如下:

    typedef struct _IMAGE_IMPORT_DESCRIPTOR {
        union {
            DWORD   Characteristics;
            DWORD   OriginalFirstThunk;             //导入名称表(INT)的地址RVA
        } DUMMYUNIONNAME;
        DWORD   TimeDateStamp;                      //时间戳多数情况可忽略.如果是0xFFFFFFFF为绑定导入
        DWORD   ForwarderChain;                     //链表的前一个结构
        DWORD   Name;                               //导入DLL文件名的地址RVA
        DWORD   FirstThunk;                         //导入地址表(IAT)的地址RVA
    } IMAGE_IMPORT_DESCRIPTOR;
    typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
    
    //成员OriginalFirstThunk与FirstThunk都指向此结构:
    typedef struct _IMAGE_THUNK_DATA32 {
        union {
            DWORD ForwarderString;      // PBYTE
            DWORD Function;             // PDWORD
            DWORD Ordinal;              // 序号
            DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
        } u1;
    } IMAGE_THUNK_DATA32;
    typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;
    
    //如果结构IMAGE_THUNK_DATA32成员最高有效位(MSB)为1时低31位为导出序号.否则指向此结构.
    typedef struct _IMAGE_IMPORT_BY_NAME {
        WORD    Hint;   //导出序号(有些编译器不会填充此值)
        CHAR   Name[1]; //该值长度不准确,以0结尾的字符串.导出函数名.
    } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

    定位导入表:

    IMAGE_OPTIONAL_HEADER -> DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT(1)].VirtualAddress + ImageBase.(如果在文件中解析只需将RVA转换为FOA加上当前文件首地址即可定位导入表).

    通过WinHex工具查看PE文件默认属性

    上述解析得知:

    内存对齐 = 1000h

    文件对齐 = 1000h

    导出表RVA = 0x00022A10(对齐相同FOA为0x00022A10h)(RVA与FOA转换讲解)

    前两个导入表解析如下:

    成员含义:

    Name该成员为DLL名指针,指向以"\0"结尾的ANIS字符串(RVA).

    第一个导入表指向00022FFCh.对应字符串数据为: MFC42.DLL

    第二个导入表指向00023096h.对应字符串数据为: MSVCRT.dll

    OriginalFirstThunk该成员为导入名称表(INT import name table)RVA,指向IMAGE_THUNK_DATA结构体数组,通过结构体成员是否为0来判断结束标记.该成员解析存在两种状态,当最高有效位为1时低31位为函数导出序号,否则为RVA指向结构体IMAGE_IMPORT_BY_NAME.

    第一个导入表指向00022AC8h.对应数据为:

    指向数据MSB均为1(低31位为导出函数序号)

    第二个导入表指向00022F28h.对应数据为:

    指向数据MSB均为0(该值为RVA指向IMAGE_IMPORT_BY_NAME结构体)

    FirstThunk该成员为导入地址表(IAT import address table)RVA,在程序运行前同OriginalFirstThunk结构一样通过判断MSB来决定存储内容.程序运行时,还是指向IMAGE_THUNK_DATA结构体数组,但是内容为对应函数地址.

    第一个导入表指向0001D040h.对应数据为:

    文件运行前同INT表指向数据一样

     第二个导入表指向0001D4A0h.对应数据为:

    文件运行前同INT表指向数据一样

    通过文件解析可以获得如下数据:

    第一个导入表:

    第二个导入表:

    导入表定位以及解析(手动ImageBuffer)

    运行程序,通过WinHex解析内存中对应INT 和 IAT数据

    文件ImageBase为400000h,只需将之前解析值(RVA)+ImageBase即可.

    第一个导入表:

    OriginalFirstThunk

    第一个导入表指向00022AC8h + ImageBase(400000h).对应数据为:

    与文件中数据一致,并未发生任何改变.

    FirstThunk

    第一个导入表指向0001D040h+ ImageBase(400000h).对应数据为:

    通过OD / DBG 查看对应数据

    运行时IAT表中存储的值61E3FFF0h为内存中真正函数地址

    MFC42.DLL模块

    通过内存解析可以获得如下数据:

    如果要实现内存加载,无模块等都需要用到导入表.解析导入表获得导入模块,通过函数名或者序号去对应模块导出表中查找对应函数地址并填充IAT表.

    导出表详解(可自行实现API GetProcAddress)

    代码定位导入表并打印其数据

    读取文件代码

    PVOID FileToMem(IN PCHAR szFilePath, OUT LPDWORD dwFileSize)
    {
    	//打开文件
    	FILE* pFile = fopen(szFilePath, "rb");
    	if (!pFile)
    	{
    		printf("FileToMem fopen Fail \r\n");
    		return NULL;
    	}
     
    	//获取文件长度
    	fseek(pFile, 0, SEEK_END);			//SEEK_END文件结尾
    	DWORD Size = ftell(pFile);
    	fseek(pFile, 0, SEEK_SET);			//SEEK_SET文件开头
     
    	//申请存储文件数据缓冲区
    	PCHAR pFileBuffer = (PCHAR)malloc(Size);
    	if (!pFileBuffer)
    	{
    		printf("FileToMem malloc Fail \r\n");
    		fclose(pFile);
    		return NULL;
    	}
     
    	//读取文件数据
    	fread(pFileBuffer, Size, 1, pFile);
     
    	//判断是否为可执行文件
    	if (*(PSHORT)pFileBuffer != IMAGE_DOS_SIGNATURE)
    	{
    		printf("Error: MZ \r\n");
    		fclose(pFile);
    		free(pFileBuffer);
    		return NULL;
    	}
     
    	if (*(PDWORD)(pFileBuffer + *(PDWORD)(pFileBuffer + 0x3C)) != IMAGE_NT_SIGNATURE)
    	{
    		printf("Error: PE \r\n");
    		fclose(pFile);
    		free(pFileBuffer);
    		return NULL;
    	}
     
    	if (dwFileSize)
    	{
    		*dwFileSize = Size;
    	}
     
    	fclose(pFile);
     
    	return pFileBuffer;
    }

    输出文件代码

    VOID MemToFile(IN PCHAR szFilePath, IN PVOID pFileBuffer, IN DWORD dwFileSize)
    {
    	//打开文件
    	FILE* pFile = fopen(szFilePath, "wb");
    	if (!pFile)
    	{
    		printf("MemToFile fopen Fail \r\n");
    		return;
    	}
     
    	//输出文件
    	fwrite(pFileBuffer, dwFileSize, 1, pFile);
     
    	fclose(pFile);
    }

    定位并输出导入表数据

    VOID PrintImportInfo()
    {
    	//读取文件二进制数据
    	DWORD dwFileSize = 0;
    	PCHAR pFileBuffer = FileToMem(FILE_PATH_IN, &dwFileSize);
    	if (!pFileBuffer)
    	{
    		return;
    	}
    
    	//定位结构
    	PIMAGE_DOS_HEADER        pDos = (PIMAGE_DOS_HEADER)pFileBuffer;
    	PIMAGE_NT_HEADERS        pNth = (PIMAGE_NT_HEADERS)(pFileBuffer + pDos->e_lfanew);
    	PIMAGE_FILE_HEADER		 pFil = (PIMAGE_FILE_HEADER)((PUCHAR)pNth + 4);
    	PIMAGE_OPTIONAL_HEADER32   pOpo = (PIMAGE_OPTIONAL_HEADER32)((PUCHAR)pFil + IMAGE_SIZEOF_FILE_HEADER);
    
    	//判断该PE文件是否有重定位表
    	if (!pOpo->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
    	{
    		printf("该PE文件不存在导入表 \r\n");
    		return;
    	}
    	PIMAGE_IMPORT_DESCRIPTOR pImp = (PIMAGE_IMPORT_DESCRIPTOR)(pFileBuffer + RvaToFoa(pFileBuffer, pOpo->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
    
    	//循环遍历
    	while (pImp->OriginalFirstThunk && pImp->FirstThunk)
    	{
    		printf("-----------------------------------------------------------\r\n");
    		PUCHAR pDllName = pFileBuffer + RvaToFoa(pFileBuffer, pImp->Name);
    		printf("ModuleName -> [%s] \r\n", pDllName);
    
    		
    		//遍历INT
    		printf("*****************INT*****************\r\n");
    		PIMAGE_THUNK_DATA pInt = (PIMAGE_THUNK_DATA)(pFileBuffer + RvaToFoa(pFileBuffer, pImp->OriginalFirstThunk));
    		do
    		{
    			//判断最高位
    			if (*(PDWORD)pInt & IMAGE_ORDINAL_FLAG32)//IMAGE_ORDINAL_FLAG32 0x80000000
    			{
    				printf("ExportByOriginal -> [0x%08x] \r\n", *(PDWORD)pInt & 0x7FFFFFFF);
    			}
    			else
    			{
    				PIMAGE_IMPORT_BY_NAME pTemp = (PIMAGE_IMPORT_BY_NAME)(pFileBuffer + RvaToFoa(pFileBuffer, *(PDWORD)pInt));
    				printf("ExportByName -> HINT[0x%04x] NAME[%s] \r\n", pTemp->Hint, pTemp->Name);
    			}
    
    		} while (*(PDWORD)(++pInt));
    
    
    		//遍历IAT
    		printf("*****************IAT*****************\r\n");
    		PIMAGE_THUNK_DATA pIat = (PIMAGE_THUNK_DATA)(pFileBuffer + RvaToFoa(pFileBuffer, pImp->FirstThunk));
    
    		//判断是否为绑定导入
    		if (pImp->TimeDateStamp == 0)
    		{
    			do
    			{
    				//判断最高位
    				if (*(PDWORD)pIat & IMAGE_ORDINAL_FLAG32)//IMAGE_ORDINAL_FLAG32 0x80000000
    				{
    					printf("ExportByOriginal -> [0x%08x] \r\n", *(PDWORD)pIat & 0x7FFFFFFF);
    				}
    				else
    				{
    					PIMAGE_IMPORT_BY_NAME pTemp = (PIMAGE_IMPORT_BY_NAME)(pFileBuffer + RvaToFoa(pFileBuffer, *(PDWORD)pIat));
    					printf("ExportByName -> HINT[0x%04x] NAME[%s] \r\n", pTemp->Hint, pTemp->Name);
    				}
    
    			} while (*(PDWORD)(++pIat));
    		}
    		else
    		{
    			do
    			{
    				printf("FunAddr -> [0x%08x] \r\n", *(PDWORD)pIat);
    
    			} while (*(PDWORD)(++pIat));
    			
    		}
    
    		//指向下一个导入表结构
    		pImp++;
    	}
    
    }
    展开全文
  • 14.导入表注入

    千次阅读 2021-10-31 21:53:45
    导入表注入 涉及知识导入表,绑定导入表. 新增节用来存储新导入表 复制默认导入表数据到新增节起始位置,并修正IMAGE_OPTIONAL_HEADER目录项中VirtualAddress 在默认导入表结构后追加一个导入表并修正其成员. ...
  • 下载 非开源,下载...根据代码段调用的API函数,对内存中进程的导入表相关结构进行修复。 使用方法: 打开主界面: 填入进程ID,代码段的起始位置,代码段后面段的起始位置(代码段结束位置+1) 新..
  • Oracle导出导入表结构操作

    千次阅读 2022-01-19 11:43:01
    Oracle导出导入表操作方法一 1.Plsql —工具 — 导出用户对象 2.输出文件路径查看导出的xx.sql文件 3.数据库A导表进数据库B,先在B库建立相同的表空间 临时表空间可不需要 创建表空间 create tablespace USER_DEF...
  • PE结构&延迟加载导入表

    千次阅读 2021-02-04 14:41:12
    延迟加载导入表是PE中引入的专门用来描述与动态链接库延迟加载相关的数据,因为这些数据所起的作用和导入表数据基本一致,所以称为延迟加载导入表。 延迟加载导入表导入表是相互分离的,一个PE文件中可以同时存在...
  • 导入表的解析及遍历

    千次阅读 2018-12-05 18:13:41
    一个PE文件中的导入表,简单来说就是代表了该模块调用了哪些外部的API。当模块加载到内存后,PE加载器会修改该表,将导入地址表也就是常说的IAT修改为外部API重定位后的真实地址。下面结合实际PE文件来详细分析下导入...
  • Oracle如何导出导入表及数据?我们知道Oracle导出导入表及数据,包括含有clob和blob数据的表数据,那么具体该怎么操作?且看下文。具体方法如下:解决方法1:1、导出导入表和数据,最快的还是在plsql工具里选择导出...
  • 达梦数据库提供了图形化界面进行数据导出导入,下面对这些功能做下演示说明: 打开图形化界面:安装目录–>tool目录–>运行./manager 打开后的界面: 导出步骤一: 导出步骤二: 选择要存放的目录,填写...
  • 当PE文件被加载到内存时,加载器会先检查导入表,然后把需要加载的DLL载入到地址空间中. 加载器还有一项比较重要的工作是根据导入信息的描述使用动态链接库里输入函数的实际地址去替换IAT表的内容,这个步骤会花去一...
  • Mysql——将CSV文件导入表

    千次阅读 2021-01-18 18:59:39
    本教程展示如何用LOAD DATA INFILE 将 CSV 文件导入MySQL中。LOAD DATA INFILE 语句可以读取文本文件并导入数据库中。在导入文件之前,你需要做如下准备:导入文件的目标数据库csv文件的列与目标数据库的列的...
  • oracle imp导入 只导入表数据

    千次阅读 2020-01-04 11:32:04
    对于oracle 11g imp有一个参数,data_only, 默认为 N imp 中 添加 data_only=y 即可
  • 手动添加导入表修改EXE功能

    千次阅读 2016-10-30 15:35:34
    手动添加导入表修改EXE功能
  • 1、导入表(Import Descriptor)结构解析:导入表是记录PE文件中用到的动态连接库的集合,一个dll库在导入表中占用一个元素信息的位置,这个元素描述了该导入dll的具体信息。如dll的最新修改时间、dll中函数的名字/...
  • Windows PE 第四章 导入表

    千次阅读 2016-10-07 21:15:28
    Windows PE 第四章 导入表
  • idea的Database导出导入表操作

    千次阅读 2021-10-19 11:36:46
    1. 导出数据: 选中多个: 左键 + shift (不松手) + 左键 下载结构数据:在选中上右键--Dump data to file -- 勾选: add table definition -- SQL insertS -- 选择或者新建目录--...导入数据: 在...
  • navicat 工具导出导入表结构及数据教程一、 导出二、导入 一、 导出 通过navicat连接数据库成功后,选中要导出的表或数据库名称,点击 “工具—数据传输”后,打开如下截图: "在源—数据库对象–表"中,可以...
  • oracle数据库导入表的方式

    千次阅读 2019-07-04 20:26:48
    1、 选择工具 2、选择导入表 3、选择需要导入的文件格式及路径 4、 选择路径之后的导入 5、导入之后来这里查找
  • Navicat中导入表的方法

    万次阅读 2019-04-15 16:53:20
    有2种方法可以在Navicat中导入表和数据,一种是导入.sql文件,另一种是用Navicat中的 数据传输 功能。 第一种方法: 1. 对一张表右键,选择“转储SQL文件”,选择“结构和数据”,选择文件名a和路径,然后保存。 ...
  • 改写PE文件导入表加载DLL

    热门讨论 2010-03-18 09:45:37
    通过改写PE文件的导入段,实现DLL的加载。PE文件的导入段记录了系统所要加载的DLL名,以及由该DLL所导出的,PE文件中所用到的函数信息。
  • Powerdesigner通过sql脚本导入表结构

    千次阅读 2018-07-02 15:25:57
    Database ,选择数据库类型单击“确定”以后出现以下截图:导入sql脚本,然后单击“确定”,成功导入后powerdesign中会生成一张PhysicalDiagram文件,里面包含你导入的所有结构;其他数据库的导入方式同理。...
  • 今天遇到一个之前的旧项目,需要重新梳理功能,有一些结构需要修改,由于需要维护多个数据库的脚本,直接修改SQL不是很方便,之前的pdm文件早已不知踪影,所以想到用PowerDesigner来维护结构然后直接导出多个...
  • mysql 导出/导入表结构和表数据

    万次阅读 2019-04-26 19:19:58
    一、导出 命令行下具体用法如下: ... 脚本名; 导出整个数据库结构和数据 mysqldump -h localhost -uroot -p123456 database >...导出单个数据结构和数据 mysqldump -h localhost -uroot -p123456 d...
  • PLSQL 导出、导入 和数据

    万次阅读 2018-09-10 11:20:06
    勾选 “Create tables” 是因为在导入的数据库中没有此 如果勾选"Drop tables" 而没有勾选 “Create tables” ,而数据库中没有此,会报表和视图不存在 Output file 为导出的路径 如果你想导的 数据...
  • 在imp导入的时候,如果存在的话,会追加数据在中,所以如果不想追加在中的话,需要将想导入truncate掉后,在impSQL:truncate table TEST1;imp test/test file=test.dmp tables=test1 ignore=y buffer=...
  • IMP只导入表数据

    万次阅读 2017-07-18 11:02:25
    imp mycim/mycim file=njdq20170705.dmp indexes=n grants=n constraints=n statistics=none fromuser=mycim touser=mycim ignore=y
  • oracle数据库——impdp导入表空间

    千次阅读 2018-11-11 16:50:37
    关于oracle导入导出这是其中一种方法,有很多地方自己还不明白。写的不好的地方大家也可以指出来,一起学习。 导入 ...  [创建用户]: create user user_name identified by password;... [创建...
  • 用beeline将数据导入表

    千次阅读 2019-05-16 21:43:29
    用beeline将数据导入表中,需要先将文件上传到hadoop,比如上传到tmp下:hadoop fs -put 路径/data.txt /tmp/ 然后进到beeline里面执行:load data inpath '/tmp/data.txt' overwrite into table 表名 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 698,214
精华内容 279,285
关键字:

导入表