首页
社区
课程
招聘
[原创]PE文件之旅 -- 第三篇 加壳与脱壳的战场 输入表(俯源码)
发表于: 2005-1-7 17:13 9316

[原创]PE文件之旅 -- 第三篇 加壳与脱壳的战场 输入表(俯源码)

2005-1-7 17:13
9316

PE文件之旅(C语言描述) 第三篇 -- 加壳与脱壳的战场 输出表
       
        呼~,终于到输入表了,No Wasting Time, Let's Go!
        还是讲原理先。输入表较前一篇的输出表稍微复杂一些,所谓复杂,在C语言里,无非就是多了

几重指针,通过多重指针找啊找的才能访问到想要的东西。就好象你拿着钱找绑匪(T),到了T指定的地点

,接了个电话,T又指定了一个新的地点,于是你到了T指定的新的地点... 呵呵,开个玩笑。上一篇我们

在IMAGE_OPTIONAL_HEADER32.DataDirectory的第一个数组里面找到了输出表,第二个元素描述的就是输

入表的信息。大家还记得这个DataDirectory结构数组吧?它是IMAGE_DATA_DIRECTORY结构,有必要再重

申一下它的定义:

                typedef struct _IMAGE_DATA_DIRECTORY {
                           DWORD   VirtualAddress;
                            DWORD   Size;
                        } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
想起来了吧,ViretualAddress就指向输出表(接到绑匪电话了,呵呵)。还等什么?我们开始吧!

核心代码:

// 首先定位IMAGE_OPTIONAL_HEADER32结构
IMAGE_OPTIONAL_HEADER32 myOptionalHeader;
fseek(pFile, (e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER)), SEEK_SET);     // 如此

定位的原因请参考PE文件结构图
fread(&myOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER32), 1, pFile);

// 将输入表的VA转换为文件偏移
dwFileOffset = OnConvertVAToRawA(myOptionalHeader.DataDirectory[1].VirtualAddress);
if (dwFileOffset != -1)
{
        printf("输入表的文件偏移为:%08x\n", dwFileOffset);
        // 输入表由IMAGE_IMPORT_DESCRIPTOR结构数组开始,每一个被隐式调用的DLL文件都会有一个

对应的IID结构数组
        // 但是没有字段指明IID数组的个数,也就是引入的DLL文件个数,但是这个IID数组的最后一个

元素全为0,
        // 通过这一点可以计算出引入的DLL文件的个数,也就是IID结构数组的元素个数。
        // IMAGE_IMPORT_DESCRIPTOR结构定义:
        // typedef struct _IMAGE_IMPORT_DESCRIPTOR {
        // union {
        // DWORD   Characteristics;                 // 0 for terminating null import

descriptor
        // DWORD   OriginalFirstThunk;              // RVA to original unbound IAT

(PIMAGE_THUNK_DATA)
           // };
           // DWORD   TimeDateStamp;                   // 0 if not bound,
                                                     // -1 if bound, and real date\time stamp
                                                        // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT

(new BIND)
                                                        // O.W. date/time stamp of DLL bound to

(Old BIND)

           // DWORD   ForwarderChain;                  // -1 if no forwarders
           // DWORD   Name;
           // DWORD   FirstThunk;                      // RVA to IAT (if bound this IAT has

actual addresses)
        // } IMAGE_IMPORT_DESCRIPTOR;
        // 现在已经获得了输入表的文件偏移,所以从这里开始就是输入表的IID数组了
        IMAGE_IMPORT_DESCRIPTOR IID;
        fseek(pFile, dwFileOffset, SEEK_SET);
        fread(&IID, sizeof(IMAGE_IMPORT_DESCRIPTOR), 1, pFile);
        // 得到IID数组个数先
        int nDllCount = 0;
        while ((0 != IID.Characteristics) || (0 != IID.FirstThunk) || (0 !=

IID.ForwarderChain) || (0 != IID.Name) || (0 != IID.OriginalFirstThunk) || (0 !=

IID.TimeDateStamp) )
        {
                nDllCount++;
                fread(&IID, sizeof(IMAGE_IMPORT_DESCRIPTOR), 1, pFile);
        }
        printf("导入的DLL个数为:%d\n", nDllCount);

        // 已经得到了导入的DLL个数,现在把他们读出来
        IMAGE_IMPORT_DESCRIPTOR *pIID = (IMAGE_IMPORT_DESCRIPTOR *)calloc(nDllCount, sizeof

(IMAGE_IMPORT_DESCRIPTOR)); // prince 01
        fseek(pFile, dwFileOffset, SEEK_SET);
        fread(pIID, sizeof(IMAGE_IMPORT_DESCRIPTOR), nDllCount, pFile);

        // IID.Name中存放的就是DLL文件的名称的地址,注意是地址而不是以Zero结尾的字符串.
        // --------------------- 通过IID.Name的RVA读出DLL的名称 ----------------------- //
        DWORD *pNameFileOffset = (DWORD *)malloc(sizeof(DWORD) * nDllCount); // prince 02
        // 取出这些Name的VA转化为FileOffset存在pNamefileOffset中
        for (int i = 0; i < nDllCount; i++, pNameFileOffset++, pIID++)
        {
                *pNameFileOffset = OnConvertVAToRowA(pIID->Name);
        }
        // 恢复指针
        pIID            -= nDllCount;
        pNameFileOffset -= nDllCount;
       
        // 动态开辟指针数组pName,*pName指向存着DLL Name的pchName
        DWORD *pName = (DWORD *)calloc(nDllCount, sizeof(DWORD));  // prince 03 必须和04一起

释放
        for (i = 0; i < nDllCount; i++, pName++)
        {
                // 每次开辟一个chName[16]用于存放Name
                char *pchName = (char *)malloc(sizeof(char) * 16);     // prince 04 必须和03

一起释放
                // 将本次申请的内存的地址保存到*pName中
                *pName = (DWORD)pchName;
        }
        // 恢复指针
        pName -= nDllCount;
        // 以上动态分配内存的部分实际上是二重指针,这里这样分配好理解一些,下面再遇见同样的

问题就直接声明多重指针了
        // 读取Name
        for (i = 0; i < nDllCount; i++, pNameFileOffset++, pName++)
        {
                DWORD dwDllName = *pNameFileOffset;
                fseek(pFile, dwDllName, SEEK_SET);
                char chTemp[16] = {0};
                fread((void *)*pName, 16, 1, pFile);
        }
        pNameFileOffset -= nDllCount;
        pName           -= nDllCount;

        if (pNameFileOffset != NULL)                                // release prince 02
        {
                free(pNameFileOffset);
                pNameFileOffset = NULL;
        }
        // --------------- pName中就是每个DLL文件名称的文件偏移地址 ------------------- //

        // 读取IMAGE_IMPORT_DESCRIPTOR的OriginalFirstThunk(或Characteristics)的值,该值指向

IMAGE_THUNK_DATA结构数组,
        // IMAGE_THUNK_DATA数组的每一个指针都指向IMAGE_IMPORT_BY_NAME结构
        // 动态开辟空间用来保存每个DLL的FistThunk值(文件偏移值)
        DWORD *pFirstThunkOfFileOffset = (DWORD *)calloc(nDllCount, sizeof(DWORD));  //

prince 05
        char *pbByIndex = (char *)calloc(nDllCount, sizeof(char));                   //

prince 06
        for (i = 0; i < nDllCount; i++, pbByIndex++)
        {
                *pbByIndex = 0;
        }
        pbByIndex -= nDllCount;  // 用来判断是否函数引入的标志

        // 读出OriginalFirstThunk所指向的值,该值高位的两个字节如果是0x8000,则说明该函数是

以序号引入。
        // 低位的两个字节即为引入序号,比如该值为:0x80001234,那么就说明引入的是该DLL文件的

第1234h号函数。
        DWORD *pdwRowAddressOfOriginalFirstThunk = (DWORD *)malloc(sizeof(DWORD));      //

prince 23
        for (i = 0; i < nDllCount; i++, pIID++, pFirstThunkOfFileOffset++, pbByIndex++)
        {
                DWORD dwTemp = OnConvertVAToRawA(pIID->OriginalFirstThunk);
                fseek(pFile, dwTemp, SEEK_SET);
                fread(pdwRowAddressOfOriginalFirstThunk, sizeof(DWORD), 1, pFile);
                if (0 != *pdwRowAddressOfOriginalFirstThunk)
                {
                        struct HightBit
                        {
                                int nHightBit : 1;
                        }Bit;
                        Bit.nHightBit = *pdwRowAddressOfOriginalFirstThunk >> 31;
                        if (0 != Bit.nHightBit)  // 按序号引入函数
                        {       
                                *pbByIndex = 1;
                                *pFirstThunkOfFileOffset = OnConvertVAToRawA(pIID-

>OriginalFirstThunk);
                        }
                        else                     // 按名称引入函数
                        {
                                *pFirstThunkOfFileOffset = OnConvertVAToRawA(pIID-

>OriginalFirstThunk);
                        }
                }
                else
                {
                        *pFirstThunkOfFileOffset = OnConvertVAToRawA(pIID->FirstThunk);
                }
        }
        // 恢复指针
        pIID                        -= nDllCount;
        pFirstThunkOfFileOffset -= nDllCount;
        pbByIndex               -= nDllCount;

        if (pdwRowAddressOfOriginalFirstThunk != NULL)               // release prince 23
        {
                free(pdwRowAddressOfOriginalFirstThunk);
                pdwRowAddressOfOriginalFirstThunk = NULL;
        }

        if (pIID != NULL)                        // release prince 01
        {
                free(pIID);
                pIID = NULL;
        }

        // -------------------- pFirstThunkOfFileOffset中是每个DLL入口的文件偏移值 --------

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

        // 同样,IMAGE_THUNK_DATA结构数组也是以全0作为结束,用这一点来计算出每个DLL文件的函

数个数
        // --------------------------------- 读取每个DLL的函数的个数 ----------------------

---------- //
        int *pnFunctionCountPerDll = (int *)calloc(nDllCount, sizeof(int));                  

// prince 07
        IMAGE_THUNK_DATA *pITD = (IMAGE_THUNK_DATA *)malloc(sizeof(IMAGE_THUNK_DATA));      

// prince 08
        for (i = 0; i < nDllCount; i++, pnFunctionCountPerDll++, pFirstThunkOfFileOffset++)
        {
                fseek(pFile, *pFirstThunkOfFileOffset, SEEK_SET);
                fread(pITD, sizeof(IMAGE_THUNK_DATA), 1, pFile);
                int nFunctionCount = 0;
                while ((pITD->u1.ForwarderString != 0) || (pITD->u1.Function != 0) || (pITD

->u1.Ordinal != 0) || (pITD->u1.AddressOfData != 0))
                {
                        nFunctionCount++;
                        fread(pITD, sizeof(IMAGE_THUNK_DATA), 1, pFile);
                }
                *pnFunctionCountPerDll = nFunctionCount;
        }
        if (pITD != NULL)                    // release prince 08
        {
                free(pITD);
                pITD = NULL;
        }

        pFirstThunkOfFileOffset -= nDllCount;
        pnFunctionCountPerDll        -= nDllCount;
        // ---------------- pnFunctionCountPerDll中存放的就是每个DLL中引入的函数个数 ------

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

        // 由于DLL文件的个数,每个DLL文件的函数个数都是不固定的,所以这里我用了三重指针。
        // 也许用了三重指针使下面的程序难懂了一些,但是我认为这是最好的方法了。
        // ------------------------------ 读取每个DLL文件中函数的名称 ---------------------

---------- //
        DWORD ***pdwFunctionOfDll = (DWORD ***)calloc(nDllCount, sizeof(DWORD**));           

           // prince 09 必须和10,11一起释放
        for (i = 0; i < nDllCount; i++, pdwFunctionOfDll++, pnFunctionCountPerDll++)
        {
                DWORD **pdwFileOffsetOfFunction = (DWORD **)calloc(*pnFunctionCountPerDll,

sizeof(char*));  // prince 10 必须和09,11一起释放
                *pdwFunctionOfDll = pdwFileOffsetOfFunction;
                for (int j = 0; j < *pnFunctionCountPerDll; j++, pdwFileOffsetOfFunction++)
                {
                        char *pchFunctionName = (char *)malloc(sizeof(char) * 64);           

                   // prince 11 必须和09,10一起释放
                        *pdwFileOffsetOfFunction = (DWORD *)pchFunctionName;
                }
        }
        pdwFunctionOfDll                -= nDllCount;
        pnFunctionCountPerDll        -= nDllCount;
                       
        // ----------------------- 确定哪几个DLL文件是序号引入 ----------------------------

//
        int nByIndexDllCount                  = 0;
        for (i = 0; i < nDllCount; i++, pbByIndex++)
        {
                if (0 != *pbByIndex)
                {
                        nByIndexDllCount++;
                }
        }
        pbByIndex -= nDllCount;
        // ----------------------- 有nByIndexDllCount个DLL文件是由序号引入的 --------------

----- //

        // ----------------------- 再求出每个由序号引入的DLL的函数个数 --------------------

-- //
        int *pnByIndexDllFunctionsCount = (int *)calloc(nByIndexDllCount, sizeof(int));      

            // prince 24
        for (i = 0; i < nDllCount; i++, pbByIndex++, pnFunctionCountPerDll++)
        {
                if (0 != *pbByIndex)
                {
                        *pnByIndexDllFunctionsCount = *pnFunctionCountPerDll;
                        pnByIndexDllFunctionsCount++;
                }
        }
        pbByIndex                                   -= nDllCount;
        pnFunctionCountPerDll           -= nDllCount;
        pnByIndexDllFunctionsCount -= nByIndexDllCount;
        // ------------------- pnByIndexDllFunctionsCount所指向的就是每个由序号引入的DLL文件

的函数个数 ---------------- //

        // ------------------ 动态开辟内存用来保存由序号引入的函数序号 --------------------

---- //
        DWORD **pdwFunctionIndex = (DWORD **)calloc(nByIndexDllCount, sizeof(DWORD *));      

             // prince 25
        for (i = 0; i < nByIndexDllCount; i++, pnByIndexDllFunctionsCount++,

pdwFunctionIndex++)
        {
                DWORD *pdwFunctionIndexTmp = (DWORD *)calloc(*pnByIndexDllFunctionsCount,

sizeof(DWORD));    // prince 26
                *pdwFunctionIndex = pdwFunctionIndexTmp;
        }
        pnByIndexDllFunctionsCount -= nByIndexDllCount;
        pdwFunctionIndex           -= nByIndexDllCount;
        // --------------------------------------------------------------------------------

------//

        for (i = 0; i < nDllCount; i++, pFirstThunkOfFileOffset++, pnFunctionCountPerDll++,

pdwFunctionOfDll++, pbByIndex++)
        {
                IMAGE_THUNK_DATA *pITD = (IMAGE_THUNK_DATA *)calloc(*pnFunctionCountPerDll,

sizeof(IMAGE_THUNK_DATA)); // prince 12
                fseek(pFile, *pFirstThunkOfFileOffset, SEEK_SET);
                fread(pITD, sizeof(IMAGE_THUNK_DATA), *pnFunctionCountPerDll, pFile);
                DWORD dwFileOffsetOfFunction;
                if (0 == *pbByIndex)
                {
                        for (int j = 0; j < *pnFunctionCountPerDll; j++, pITD++)
                        {
                                dwFileOffsetOfFunction = OnConvertVAToRowA((DWORD)pITD-

>u1.AddressOfData);
                                fseek(pFile, dwFileOffsetOfFunction + 2, SEEK_SET);
                                fread((void *)**pdwFunctionOfDll, 64, 1, pFile);
                                strText.Format("%s", **pdwFunctionOfDll);
                                (*pdwFunctionOfDll)++;
                        }
                        pITD -= *pnFunctionCountPerDll;
                        *pdwFunctionOfDll -= *pnFunctionCountPerDll;
                }
                else
                {
                        for (int j = 0; j < *pnByIndexDllFunctionsCount; j++, pITD++,

(*pdwFunctionIndex)++)
                        {
                                **pdwFunctionIndex = (DWORD)pITD->u1.AddressOfData;
                        }
                        pITD -= *pnByIndexDllFunctionsCount;
                        *pdwFunctionIndex -= *pnByIndexDllFunctionsCount;
                        pnByIndexDllFunctionsCount++;
                        pdwFunctionIndex++;
                }
                               
                if (pITD != NULL)                         // release prince 12
                {
                        free(pITD);
                        pITD = NULL;
                }
                               
        }

        if (nByIndexDllCount != 0)
        {
                pnByIndexDllFunctionsCount -= nByIndexDllCount;
                pdwFunctionIndex           -= nByIndexDllCount;
        }

        pdwFunctionOfDll                -= nDllCount;
        pFirstThunkOfFileOffset -= nDllCount;
        pnFunctionCountPerDll   -= nDllCount;
        pbByIndex               -= nDllCount;

        if (pFirstThunkOfFileOffset != NULL)               // release prince 05
        {
                free(pFirstThunkOfFileOffset);
                pFirstThunkOfFileOffset = NULL;
        }
        // -------------------------- 三重指针pdwFunctionOfDll最终指向函数名称 ------------

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

        // --------------------- 处理由序号引入的函数的序号 --------------------------------

//

        for (i = 0; i < nDllCount; i++, pName++, pnFunctionCountPerDll++,

pdwFunctionOfDll++, pbByIndex++)
        {
                prince("DLL %d 名字:%s\n", (i + 1), *pName);
                prince("调用函数个数:%d\n", *pnFunctionCountPerDll);
                if (0 == *pbByIndex)
                {
                        for (int j = 0; j < *pnFunctionCountPerDll; j++,

(*pdwFunctionOfDll)++)
                        {
                                prince("%s\n", **pdwFunctionOfDll);
                        }
                        *pdwFunctionOfDll -= *pnFunctionCountPerDll;
                }
                else
                {
                        prince("此DLL文件中函数由序号引入!");
                        for (int j = 0; j < *pnByIndexDllFunctionsCount; j++,

(*pdwFunctionIndex)++)
                        {
                                prince("引入序号: %04x\n", ((**pdwFunctionIndex) & 0xffff));

  // 取0x80000000的后两个字节
                                m_ListBox1.AddString(strText);
                        }
                        *pdwFunctionIndex -= *pnByIndexDllFunctionsCount;
                        pnByIndexDllFunctionsCount++;
                        pdwFunctionIndex++;
                }

        }

        // 恢复指针
        pName                                  -= nDllCount;
        pnFunctionCountPerDll -= nDllCount;
        pdwFunctionOfDll      -= nDllCount;
        pbByIndex             -= nDllCount;

        pnByIndexDllFunctionsCount -= nByIndexDllCount;
        pdwFunctionIndex           -= nByIndexDllCount;

        for (i = 0; i < nDllCount; i++, pName++)                   // release prince 04
        {
                if (*pName != NULL)
                {
                        free((void *)*pName);
                        *pName = NULL;
                }
        }
        pName -= nDllCount;
        if (pName != NULL)                                        // release prince 03
        {
                free(pName);
                pName = NULL;
        }

        if (pbByIndex != NULL)                                        // release prince 06
        {
                free(pbByIndex);
                pbByIndex = NULL;
        }

        for (i = 0; i < nDllCount; i++, pdwFunctionOfDll++, pnFunctionCountPerDll++)     //

release prince 11
        {
                for (int j = 0; j < *pnFunctionCountPerDll; j++, (*pdwFunctionOfDll)++)
                {
                        if (**pdwFunctionOfDll != NULL)
                        {
                                free((void *)**pdwFunctionOfDll);
                                **pdwFunctionOfDll = NULL;
                        }
                }
                *pdwFunctionOfDll -= *pnFunctionCountPerDll;
        }
        pnFunctionCountPerDll -= nDllCount;
        pdwFunctionOfDll      -= nDllCount;

        for (i = 0; i < nDllCount; i++, pdwFunctionOfDll++)     // release prince 10
        {
                if (*pdwFunctionOfDll != NULL)
                {
                        free(*pdwFunctionOfDll);
                        *pdwFunctionOfDll = NULL;
                }
        }
        pdwFunctionOfDll -= nDllCount;

        if (pdwFunctionOfDll != NULL)                           // release prince 09
        {
                free(pdwFunctionOfDll);
                pdwFunctionOfDll = NULL;
        }

        if (pnFunctionCountPerDll != NULL)                                                //

release prince 07
        {
                free(pnFunctionCountPerDll);
                pnFunctionCountPerDll = NULL;
        }

        if (pnByIndexDllFunctionsCount != NULL)                 // release prince 24
        {
                free(pnByIndexDllFunctionsCount);
                pnByIndexDllFunctionsCount = NULL;
        }

        for (i = 0; i < nByIndexDllCount; i++, pdwFunctionIndex++)   // release prince 26
        {
                if (*pdwFunctionIndex != NULL)
                {
                        free(*pdwFunctionIndex);
                        *pdwFunctionIndex = NULL;
                }
        }
        pdwFunctionIndex -= nByIndexDllCount;

        if (pdwFunctionIndex != NULL)                               // release prince 25
        {
                free(pdwFunctionIndex);
                pdwFunctionIndex = NULL;
        }
}
else
{
        printf("输入表定位错误!");
}

// 计算VA到文件偏移的子程序
DWORD OnConvertVAToRawA(DWORD dwFileOffset)
{
        IMAGE_SECTION_HEADER *pmySectionHeader = (IMAGE_SECTION_HEADER *)calloc

(m_nSectionCount, sizeof(IMAGE_SECTION_HEADER)); // prince 14
        fseek(pFile, (e_lfanew + 4 + sizeof(IMAGE_FILE_HEADER) + sizeof

(IMAGE_OPTIONAL_HEADER32)), SEEK_SET);
        fread(pmySectionHeader, sizeof(IMAGE_SECTION_HEADER), m_nSectionCount, pFile);

        DWORD dwFilePos;
        DWORD dwOffset;
        DWORD *pdwVA   = (DWORD *)malloc(sizeof(DWORD) * m_nSectionCount);   // prince 15
        DWORD *pdwRowA = (DWORD *)malloc(sizeof(DWORD) * m_nSectionCount);   // prince 16
        for (int i = 0; i < m_nSectionCount; i++, pmySectionHeader++, pdwVA++, pdwRowA++)
        {
                *pdwVA   = pmySectionHeader->VirtualAddress;
                *pdwRowA = pmySectionHeader->PointerToRawData;
        }

        pmySectionHeader -= m_nSectionCount;

        pdwVA                        -= m_nSectionCount;
        pdwRowA                        -= m_nSectionCount;

        for (i = 0; i < m_nSectionCount; i++, pdwVA++, pdwRowA++)
        {
                if ((dwFileOffset >= *pdwVA) && (dwFileOffset < *(pdwVA + 1)))
                {
                        dwOffset  = *pdwVA - *pdwRowA;
                        dwFilePos = dwFileOffset - dwOffset;
                       
                        pdwVA   -= i;
                        pdwRowA -= i;
                        if (pdwVA != NULL)                       // release prince 15
                        {
                                free(pdwVA);
                                pdwVA = NULL;
                        }
                        if (pdwRowA != NULL)                     // release prince 16
                        {
                                free(pdwRowA);
                                pdwRowA = NULL;
                        }
                       
                        if (pmySectionHeader != NULL)            // release prince 14
                        {
                                free(pmySectionHeader);
                                pmySectionHeader = NULL;
                        }
                       
                        return dwFilePos;
                }
        }
        pdwVA   -= m_nSectionCount;
        pdwRowA -= m_nSectionCount;

        if (pmySectionHeader != NULL)            // release prince 14
        {
                free(pmySectionHeader);
                pmySectionHeader = NULL;
        }

        if (pdwVA != NULL)                       // release prince 15
        {
                free(pdwVA);
                pdwVA = NULL;
        }

        if (pdwRowA != NULL)                     // release prince 16
        {
                free(pdwRowA);
                pdwRowA = NULL;
        }

        return -1;
}

        PE文件之旅全部系列到此就告一段落了。在将近一个月的时间里通过对PE文件格式的研究让我从

正向的角度全面的了解了EXE文件执行的有关细节,同时对我自己而言也是得到了锻炼和提高,无奈编程

水平有限,这篇堆砌起来的垃圾代码还有着严重的不雅和缺陷,希望高手看了之后能腾出宝贵的时间对我

指点一二;同时也希望对我有着很大帮助和提高的这几篇小小的心得能让广大和我一样渴求知识和追求软

件技术的小菜们得到自己真正想要的东西。
        还是那句老话,抛砖引玉,我是就着<<PE知识学习>>写下去的。接下去我会继续研究PE文件的资

源,看看资源的压缩原理,也就是压缩壳的原理,等有了成果再和大家分享。在这里希望大家在学习知识

的同时继续把思维发展下去,真正在技术的层面上提高自己。
        现将全部VC源代码发布,希望同大家进行技术交流,程序写的较烂,请指教。

全部VC源代码和编译好的WIN32程序:
附件:PEStudy05.01.05.rar


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (16)
雪    币: 47147
活跃值: (20445)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
2
既然告一段落了,那我就干脆收进即将推出的论坛精华6里去了。:)
2005-1-7 17:16
0
雪    币: 898
活跃值: (4039)
能力值: ( LV9,RANK:3410 )
在线值:
发帖
回帖
粉丝
3
辛苦了
2005-1-7 17:16
0
雪    币: 97697
活跃值: (200824)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
4
支持!!!
2005-1-7 17:16
0
雪    币: 159
活跃值: (339)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
5
精华六 还在酝酿啊~~哎~等得着急啊~
忘了 支持了:D
2005-1-7 17:27
0
雪    币: 603
活跃值: (617)
能力值: ( LV12,RANK:660 )
在线值:
发帖
回帖
粉丝
6
最初由 kanxue 发布
既然告一段落了,那我就干脆收进即将推出的论坛精华6里去了。:)


受宠若惊!谢谢KanXue老大,两位版主fly和linhanshi的鼓励和支持。我会一直写下去的!
(下午心情受了些影响,现在全没了,哈哈,再接再厉!)
2005-1-7 17:27
0
雪    币: 97697
活跃值: (200824)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
7
最初由 prince 发布


受宠若惊!谢谢KanXue老大,两位版主fly和linhanshi的鼓励和支持。我会一直写下去的!
(下午心情受了些影响,现在全没了,哈哈,再接再厉!)


我看前途广阔,路途遥远,再接再厉!!!
2005-1-7 17:30
0
雪    币: 392
活跃值: (909)
能力值: ( LV9,RANK:690 )
在线值:
发帖
回帖
粉丝
8
当然是全力支持啦~~
prince兄弟不要误会,没说你抄袭,呵呵,我的意思是文章整理得很好
2005-1-7 17:47
0
雪    币: 603
活跃值: (617)
能力值: ( LV12,RANK:660 )
在线值:
发帖
回帖
粉丝
9
最初由 cyclotron 发布
当然是全力支持啦~~
prince兄弟不要误会,没说你抄袭,呵呵,我的意思是文章整理得很好


呵呵,没事,我这两天整理我的帖子挺累的,所以看了你的帖子有些生气,觉得劳动没有被尊重,呵呵,既然是误会,过去就算了,这可绝对是我的原创啊
2005-1-7 20:00
0
雪    币: 258
活跃值: (230)
能力值: ( LV12,RANK:770 )
在线值:
发帖
回帖
粉丝
10
1 2 1 1 2 3 4
2005-1-8 13:40
0
雪    币: 603
活跃值: (617)
能力值: ( LV12,RANK:660 )
在线值:
发帖
回帖
粉丝
11
最初由 qiweixue 发布
1 2 1 1 2 3 4


????
2005-1-8 20:31
0
雪    币: 230
活跃值: (180)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
12
兄弟辛苦!支持!!
2005-1-8 21:36
0
雪    币: 237
活跃值: (145)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
13
辛苦了,支持
1211234没错的话应该是部队中的口号,是加油用的吧
2005-1-8 22:42
0
雪    币: 603
活跃值: (617)
能力值: ( LV12,RANK:660 )
在线值:
发帖
回帖
粉丝
14
最初由 Otdr 发布
辛苦了,支持
1211234没错的话应该是部队中的口号,是加油用的吧


嘿嘿,我也是这么想D。
2005-1-8 23:00
0
雪    币: 603
活跃值: (617)
能力值: ( LV12,RANK:660 )
在线值:
发帖
回帖
粉丝
15
最初由 qINGfENG 发布
兄弟辛苦!支持!!


谢谢qINGfENG大哥,:D
2005-1-8 23:02
0
雪    币: 426
活跃值: (36)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kbs
16
看过很多介绍PE的文章,这篇也精彩啊,不比别的差:)
这种理论实践相结合的方法对于学习和记忆比较好.
再次感谢.
2005-1-9 02:39
0
雪    币: 603
活跃值: (617)
能力值: ( LV12,RANK:660 )
在线值:
发帖
回帖
粉丝
17
最初由 kbs 发布
看过很多介绍PE的文章,这篇也精彩啊,不比别的差:)
这种理论实践相结合的方法对于学习和记忆比较好.
再次感谢.


呵呵,谢谢支持,希望对你有帮助。
2005-1-9 09:14
0
游客
登录 | 注册 方可回帖
返回
//