找回密码
 立即注册
首页 业界区 安全 WindowsPE文件格式入门05.PE加载器LoadPE

WindowsPE文件格式入门05.PE加载器LoadPE

砂歹汤 2025-6-1 18:56:04
https://bpsend.net/thread-316-1-1.html
 
LoadPE - pe 加载器 壳的前身
  1. 如果想访问一个程序运行起来的内存,一种方法就是跨进程读写内存,但是跨进程读写内存需要来回调用api,不如直接访问地址来得方便,那么如果我们需要直接访问地址,该怎么做呢?.需要把dll注进程,注进去的代码跟他在同一块进程里面,这样我们就可以直接访问这个进程的地址,但是不想注入,也不想跨进程读写地址,就直接读进程地址,有什么方法呢?如果把导入表里面加一个dll,这样很容易检查出来,模块里一遍历,就可容易看到了, 其实我们可以反其道行之,换种思路,不是往他进程里面塞东西,而是把他加载到我们进程里面.,这个时候再去访问进程内存其实就是访问我们自己的内存.
复制代码
1.系统加载exe的流程


  • 准备一个新的内存;
  • 按照顺序把节表内容映射进内存;
  • 填写导入表。
2.LoadPE的目的


  • 可以在自己进程更改目标PE的内存。
3.LoadPE的重点


  • 1.在自己代码前留出足够空间--目标进程的SizeofImage;
  • 2.更改自己程序的ImageBase加载到目标ImageBase处:/base:0x。
1.png

这样,目标进程的PE头就占据了我们自己进程的 PE头,他的数据节就覆盖了我们自己的数据节,即目标进程的数据就会覆盖我们自己进程的数据,因此我们需要 把我们的代码往后移,给 目标进程 留出足够的空间
4.LoadPE的实现思路


  • 设置我们进程的 ImageBase 和 目标进程 ImageBase 保持一致
  • 我们需要把我们的代码往后移,腾出来的内存可以放目标程序
  • 读目标进程的数据,按照节表拷贝数据帮他处理导入表
  • 执行目标进程代码。
5.LoadPE的汇编实现


  • 用winhex查看目标进程的 ImageBase 和 SizeofImage
  • 新建工程,并且在工程选项设置 自己工程 的 ImageBase 与目标进程的一致
  • 后移自己的代码,可以在开头定义 SizeofImage 大小的全局变量 或者通过指令 org 偏移调整指令
注意,很多 C 库函数 并不会 保存 ecx , edx 环境,自己使用前记得先保存
进程的模块基址和 数据大小可以通过 winhex看
2.png
  1. .586
  2. .model flat,stdcall
  3. option casemap:none
  4.    include windows.inc
  5.    include user32.inc
  6.    include kernel32.inc
  7.    include msvcrt.inc
  8.    includelib user32.lib
  9.    includelib kernel32.lib
  10.    includelib msvcrt.lib
  11. IMAGE_SIZE equ 20000h     ;往后移的大小,即目标进程的SizeofImage
  12. .data
  13.     g_szFile db "winmine.exe", 0    ;要读取的进程
  14. .code
  15.     org IMAGE_SIZE 
  16. LoadPe proc
  17.     LOCAL @dwImageBase:DWORD       ;自己进程的模块基址
  18.     LOCAL @hFile:HANDLE            ;文件句柄
  19.     LOCAL @hFileMap:HANDLE         ;映射句柄
  20.     LOCAL @pPEBuf:LPVOID           ;映射文件的缓冲地址
  21.     LOCAL @pDosHdr:ptr IMAGE_DOS_HEADER      ;目标进程的dos头
  22.     LOCAL @pNTHdr:ptr IMAGE_NT_HEADERS       ;目标进程的NT头
  23.     LOCAL @pSecHdr:ptr IMAGE_SECTION_HEADER  ;目标进程的节表
  24.     LOCAL @dwNumOfSecs:DWORD                 ;目标进程的节表数量
  25.     LOCAL @pImpHdr:ptr IMAGE_IMPORT_DESCRIPTOR   ;目标进程的导入表
  26.     LOCAL @dwSizeOfHeaders:DWORD                 ;目标进程的选项头大小
  27.     LOCAL @dwOldProc:DWORD                       ;旧的内存属性
  28.     LOCAL @hdrZeroImp:IMAGE_IMPORT_DESCRIPTOR    ;导入表结束标志,所有项全0
  29.     LOCAL @hDll:HMODULE                          ;加载dll的句柄
  30.     LOCAL @dwOep:DWORD                           ;进程的入口地址
  31.     ;判断导入表结束的标志清0
  32.     invoke RtlZeroMemory, addr @hdrZeroImp, size IMAGE_IMPORT_DESCRIPTOR
  33.     ;自己的模块基址
  34.     invoke GetModuleHandle, NULL
  35.     mov @dwImageBase, eax
  36.     ;解析PE文件,获取表
  37.     ;打开文件
  38.     invoke CreateFile, offset g_szFile, GENERIC_READ, FILE_SHARE_READ,NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL
  39.     ;check ....
  40.     mov @hFile, eax   ;保存文件句柄
  41.     invoke CreateFileMapping, @hFile, NULL, PAGE_READONLY, 0, 0, NULL   ;创建文件映射
  42.     ;check
  43.     mov @hFileMap, eax    ;创建文件映射句柄
  44.     invoke MapViewOfFile, @hFileMap, FILE_MAP_READ, 0, 0, 0      ;将整个文件映射进内存
  45.     ;check 
  46.     mov @pPEBuf, eax      ;保存映射文件内存的地址
  47.     ;解析目标进程
  48.     ;目标进程的 dos 头
  49.     mov eax, @pPEBuf    
  50.     mov @pDosHdr, eax
  51.     ;目标进程的 nt头
  52.     mov esi, @pDosHdr
  53.     assume esi:ptr IMAGE_DOS_HEADER
  54.     mov eax, @pPEBuf
  55.     add eax, [esi].e_lfanew   ;获取nt头的偏移地址
  56.     mov @pNTHdr, eax
  57.     mov esi, @pNTHdr
  58.     assume esi:ptr IMAGE_NT_HEADERS
  59.     ;选项头信息
  60.     mov eax, [esi].OptionalHeader.SizeOfHeaders    ;获取选项头大小
  61.     mov @dwSizeOfHeaders, eax
  62.     ;进程的入口地址  =  进程的内存偏移地址 + 模块基址
  63.     mov eax, [esi].OptionalHeader.AddressOfEntryPoint
  64.     add eax, @dwImageBase
  65.     mov @dwOep, eax
  66.     ;节表  地址: 选项头地址+大小
  67.     movzx eax, [esi].FileHeader.NumberOfSections
  68.     mov @dwNumOfSecs,eax
  69.     lea ebx, [esi].OptionalHeader
  70.     ;获取选项头大小:用于定位节表位置=选项头地址+选项头大小
  71.     movzx eax, [esi].FileHeader.SizeOfOptionalHeader   ;把 word 转为 dword
  72.     add eax, ebx
  73.     mov @pSecHdr, eax   ;保存节表地址
  74.     ;修改内存属性
  75.     invoke VirtualProtect, @dwImageBase, IMAGE_SIZE, PAGE_EXECUTE_READWRITE, addr @dwOldProc
  76.     ;拷贝PE头  从映射内存拷贝到 自己进程的最开始处 
  77.     invoke crt_memcpy, @dwImageBase, @pPEBuf, @dwSizeOfHeaders
  78.     ;按照节表,拷贝节区数据
  79.     mov esi, @pSecHdr
  80.     assume esi:ptr IMAGE_SECTION_HEADER
  81.     xor ecx, ecx
  82.     .while ecx < @dwNumOfSecs   ;遍历节表
  83.         ;目标
  84.         mov edi, @dwImageBase
  85.         add edi, [esi].VirtualAddress  ;获取节的内存地址 + 模块地址 就是内存中的绝对地址
  86.         ;源
  87.         mov ebx, @pPEBuf
  88.         add ebx, [esi].PointerToRawData  ;获取指定进程的节数据的偏移地址  映射的首地址 + 文件偏移地址
  89.         ;大小[esi].SizeOfRawData
  90.         ;拷贝  注意,很多 C 库函数 并不会 保存 ecx ,edx 环境,自己使用前记得先保存
  91.         push ecx
  92.         push edx
  93.         invoke crt_memcpy, edi, ebx, [esi].SizeOfRawData   ;将目标进程的节数据拷贝进自己的进程
  94.         pop edx
  95.         pop ecx
  96.         inc ecx      ;计数++
  97.         add esi, size IMAGE_SECTION_HEADER  ;指针移动
  98.     .endw
  99.     ;获取导入表  如果在前面获取导入表信息,那么就需要对内存地址和文件地址做转化比较麻烦
  100.                 ;但是把数据拷贝到我们进程之后只需要访问内存进程就可以了
  101.     mov esi, @pNTHdr
  102.     assume esi:ptr IMAGE_NT_HEADERS
  103.     ;获取导入表地址 ,数组的第二个元素的第一个成员 
  104.     mov eax, [esi].OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT*8].VirtualAddress
  105.     add eax, @dwImageBase   ;获取导入表在进程的绝对地址  内存偏移 + 模块基址
  106.     mov @pImpHdr, eax       ;保存导入表的地址
  107.     ;处理导入表
  108.     mov esi, @pImpHdr
  109.     assume esi:ptr IMAGE_IMPORT_DESCRIPTOR
  110.     .while TRUE     ;遍历导入表
  111.         ;判断结束,全0项结束
  112.         invoke crt_memcmp, esi, addr @hdrZeroImp
  113.         .if eax == 0
  114.             .break
  115.         .endif
  116.         ;判断字段,为空则结束
  117.         .if [esi].Name1 == NULL || [esi].FirstThunk == NULL
  118.             .break
  119.         .endif 
  120.        ;加载dll
  121.         mov eax, [esi].Name1
  122.         add eax, @dwImageBase
  123.         push ecx
  124.         push edx
  125.         invoke LoadLibrary, eax   ;根据dll名加载 dll 
  126.         pop edx
  127.         pop ecx
  128.         ;check              如果此时为空加说明无法找到dll
  129.         mov @hDll, eax      ;保存dll的模句柄
  130.         ;获取导入地址表,IAT
  131.         mov ebx, [esi].FirstThunk
  132.         add ebx, @dwImageBase
  133.         ;获取导入名称表,INT
  134.         mov edi, ebx
  135.         .if [esi].OriginalFirstThunk != NULL
  136.             mov edi, [esi].OriginalFirstThunk
  137.             add edi, @dwImageBase          
  138.         .endif
  139.         ;遍历导入名称表
  140.         .while dword ptr [edi] != 0
  141.             .if dword ptr [edi] & 80000000h   ;判断最高位是否为1
  142.                 ;序号导入,获取序号
  143.                 mov edx, dword ptr [edi]
  144.                 and edx, 0ffffh               ;获取低 word 
  145.             .else
  146.                 ;名称导入
  147.                 mov edx, dword ptr [edi]
  148.                 add edx, @dwImageBase
  149.                 add edx, 2                  ;名称前面有2个无用字节
  150.             .endif
  151.             ;获取dll导入函数进程加载后地址
  152.             push ecx
  153.             push edx
  154.             invoke GetProcAddress, @hDll, edx
  155.             pop edx
  156.             pop ecx
  157.             ;check
  158.             ;把地址存入 INT 表
  159.             mov dword ptr [ebx], eax
  160.             add ebx, 4
  161.             add edi, 4
  162.         .endw
  163.         add esi, size IMAGE_IMPORT_DESCRIPTOR
  164.     .endw
  165.      ;清理
  166.     invoke UnmapViewOfFile,@pPEBuf
  167.     invoke CloseHandle,@hFileMap
  168.     invoke CloseHandle,@hFile
  169.     ; 执行加载的pe的代码
  170.     jmp @dwOep
  171.     ret
  172. LoadPe endp
  173. start:
  174.     invoke LoadPe
  175.     invoke ExitProcess,0
  176. end start
复制代码
  1. #include <windows.h>
  2. #include <concrt.h>
  3. #include <iostream>
  4. using namespace std;
  5. #define IMAGE_SIZE 0x5000
  6. //留空的全局变量
  7. char szBuff[IMAGE_SIZE] = { 1 };
  8. #if 1
  9. char g_szExeName[] = "PE.exe";  //需要加载的PE路径
  10. LPVOID lpMapAddr = NULL;
  11. HANDLE LoadPe()
  12. {
  13.     DWORD  dwOldProc = 0;
  14.     PIMAGE_IMPORT_DESCRIPTOR pImpHdr = NULL;
  15.     IMAGE_IMPORT_DESCRIPTOR  zeroImp = { 0 };
  16.     HANDLE hDll = NULL;
  17.     PIMAGE_THUNK_DATA pTmpThunk = NULL;
  18.     DWORD  dwPFNAddr = 0;
  19.     DWORD  dwIAT = 0;
  20.     // 获取模块句柄
  21.     HANDLE hInst = GetModuleHandle(NULL);
  22.     // 读取文件
  23.     HANDLE hFile = CreateFile(g_szExeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  24.     if (hFile == INVALID_HANDLE_VALUE)
  25.     {
  26.         return 0;
  27.     }
  28.     // 创建文件映射对象
  29.     HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  30.     if (hFileMap == NULL)
  31.     {
  32.         CloseHandle(hFile);
  33.         return 0;
  34.     }
  35.     void* lpMapAddr = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
  36.     if (lpMapAddr == NULL)
  37.     {
  38.         CloseHandle(hFileMap);
  39.         CloseHandle(hFile);
  40.         return 0;
  41.     }
  42.     // 拷贝PE头
  43.     PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpMapAddr;
  44.     PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)lpMapAddr + pDosHeader->e_lfanew);
  45.     DWORD dwSizeOfHeaders = pNtHeader->OptionalHeader.SizeOfHeaders;
  46.     DWORD dwNumOfSection = pNtHeader->FileHeader.NumberOfSections;
  47.     //获取节表首地址  (选项头地址+ 大小)
  48.     PIMAGE_SECTION_HEADER pSecHdr = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeader->FileHeader.SizeOfOptionalHeader + (DWORD)(&pNtHeader->OptionalHeader));
  49.     DWORD dwOep = (DWORD)hInst + pNtHeader->OptionalHeader.AddressOfEntryPoint;
  50.     // 更改内存属性
  51.     VirtualProtect(hInst, IMAGE_SIZE, PAGE_EXECUTE_READWRITE, &dwOldProc);
  52.     //拷贝PE头
  53.     memcpy(hInst, lpMapAddr, dwSizeOfHeaders);
  54.     // 拷贝拷贝节区数据
  55.     DWORD i = 0;
  56.     while (dwNumOfSection > i)
  57.     {
  58.         //拷贝数据
  59.         DWORD pDst = (DWORD)hInst + (DWORD)pSecHdr->VirtualAddress;
  60.         DWORD pSrc = (DWORD)lpMapAddr + (DWORD)pSecHdr->PointerToRawData;
  61.         //DWORD pSrc = (DWORD)pSecHdr;
  62.         memcpy((void*)pDst, (void*)pSrc, pSecHdr->SizeOfRawData);
  63.         int nSecHdrSzie = sizeof(IMAGE_SECTION_HEADER);
  64.         pSecHdr = (PIMAGE_SECTION_HEADER)((DWORD)pSecHdr + (DWORD)nSecHdrSzie);
  65.         i++;
  66.     }
  67.     //获取导入表地址
  68.     pImpHdr = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pNtHeader->OptionalHeader.DataDirectory[1].VirtualAddress 
  69.               + (DWORD)hInst);
  70.     // 处理导入表
  71.     while (TRUE)
  72.     {
  73.         // 遇到全0项,遍历结束 
  74.         int nRet = memcmp(pImpHdr, &zeroImp, sizeof(IMAGE_IMPORT_DESCRIPTOR));
  75.         if (nRet == 0)
  76.         {
  77.             break;
  78.         }
  79.         //判断字段, 为空则结束
  80.         if (pImpHdr->Name == NULL || pImpHdr->FirstThunk == NULL)
  81.         {
  82.             break;
  83.         }
  84.         DWORD pNameAddre = (DWORD)pImpHdr->Name + (DWORD)hInst;
  85.         // 加载dll
  86.         HMODULE hDll = LoadLibrary((LPCSTR)pNameAddre);
  87.         if (hDll == NULL)
  88.         {
  89.             break;
  90.         }
  91.         DWORD pFunAddr = 0;
  92.         DWORD pIAT = (DWORD)pImpHdr->FirstThunk + (DWORD)hInst;
  93.         DWORD pINT = (DWORD)pImpHdr->OriginalFirstThunk;
  94.         if (pINT != 0)
  95.         {
  96.             pFunAddr = pINT + (DWORD)hInst;
  97.         }
  98.         else
  99.         {
  100.             pFunAddr = pIAT;
  101.         }
  102.         // 遍历导入名称表
  103.         while (true){
  104.             DWORD pAddr = *(DWORD*)pFunAddr;
  105.             if (pAddr == 0)
  106.             {
  107.                 break;
  108.             }
  109.             DWORD  pFun = 0;
  110.             if (pAddr & 0x80000000)
  111.             {
  112.                 //序号导入, 获取序号
  113.                 pFun = pAddr & 0xffff;
  114.             }
  115.             else
  116.             {
  117.                 pFun = pAddr + 2 + (DWORD)hInst;
  118.             }
  119.             DWORD  dwPFNAddr = (DWORD)GetProcAddress(hDll, (LPCSTR)LOWORD(pFun));
  120.             *(DWORD*)pIAT = dwPFNAddr;
  121.             pIAT += 4;
  122.             pFunAddr+=4;
  123.        }
  124.         pImpHdr = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImpHdr + (DWORD)sizeof(IMAGE_IMPORT_DESCRIPTOR));
  125.     }
  126.     // 关闭句柄
  127.     UnmapViewOfFile(lpMapAddr);
  128.     CloseHandle(hFileMap);
  129.     CloseHandle(hFile);
  130.     // 返回地址
  131.     return &dwOep;
  132. }
  133. #endif // 0
  134. int main()
  135. {
  136. #if 1
  137.     // 加载PE文件,返回原OEP
  138.     void* pOep = LoadPe();
  139.     if (pOep != NULL)
  140.     {
  141.         __asm jmp pOep
  142.     }
  143. #endif // 0
  144.     return 0;
  145. }
复制代码
思路: 主要难点是代码后移,留出空间
方法1: 内联 汇编 开始 nop
方法2: 把代码放到dll中
方法3: 合并节,全局变量是放在未初始化的节内合并后就会在第一个节
合并节代码:
  1. #include <iostream>
  2. #include <Windows.h>
  3. #include <stdio.h>
  4. using namespace std;
  5. #define FILESIZE  0x00020000         //目标进程的SizeofImage
  6. #define IMAGEBASE 0x01000000
  7. char szExeDataBuff[FILESIZE] = {1};
  8. char g_szExeName[] = "winmine.exe";   //要加载的进程路径
  9. DWORD g_oep = 0;
  10. void LoadPe()
  11. {
  12.     // 创建文件映射
  13.     //打开文件
  14.     HANDLE hFile = CreateFile(g_szExeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  15.     if (hFile == INVALID_HANDLE_VALUE)
  16.     {
  17.         return ;
  18.     }
  19.     // 创建文件映射对象
  20.     HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  21.     if (hFileMap == NULL)
  22.     {
  23.         CloseHandle(hFile);
  24.         return;
  25.     }
  26.     //将文件映射进内存
  27.     LPVOID pView = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
  28.     if (pView == NULL)
  29.     {
  30.         CloseHandle(hFileMap);
  31.         CloseHandle(hFile);
  32.         return;
  33.     }
  34.     // 修改代码节属性
  35.     DWORD nOldProtect = 0;
  36.     VirtualProtect((LPVOID)IMAGEBASE, FILESIZE, PAGE_EXECUTE_READWRITE, &nOldProtect);
  37.     // 处理PE
  38.     PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pView;
  39.     // 获取pe头大小
  40.     PIMAGE_NT_HEADERS32 pNt = (PIMAGE_NT_HEADERS32)((DWORD)pView + pDos->e_lfanew);
  41.     memcpy((void*)IMAGEBASE, (void*)pDos, pNt->OptionalHeader.SizeOfHeaders);
  42.     // OEP
  43.     g_oep = pNt->OptionalHeader.AddressOfEntryPoint + IMAGEBASE;
  44.     // 解析节
  45.     PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)((DWORD) & (pNt->OptionalHeader.Magic) + pNt->FileHeader.SizeOfOptionalHeader);
  46.     // 节数量
  47.     unsigned int nNumberOfSections = pNt->FileHeader.NumberOfSections;
  48.     while (nNumberOfSections != 0)
  49.     {
  50.         void* pVirtualAddress = (void*)(pSec->VirtualAddress + IMAGEBASE);
  51.         void* pFileAddress = (void*)(pSec->PointerToRawData + (DWORD)pDos);
  52.         memcpy(pVirtualAddress, pFileAddress, pSec->SizeOfRawData);
  53.         nNumberOfSections--;
  54.         pSec++;
  55.     }
  56.     if (pNt->OptionalHeader.NumberOfRvaAndSizes > 2)
  57.     {
  58.         // 处理导入表
  59.         PIMAGE_IMPORT_DESCRIPTOR pIm = (PIMAGE_IMPORT_DESCRIPTOR)(pNt->OptionalHeader.DataDirectory[1].VirtualAddress + IMAGEBASE);
  60.         while (pIm->Name && pIm->FirstThunk)
  61.         {
  62.             HMODULE hModule = LoadLibraryA((char*)(pIm->Name + IMAGEBASE));
  63.             if (hModule == NULL)
  64.             {
  65.                 pIm++;
  66.                 continue;
  67.             }
  68.             DWORD dwThunkData = pIm->OriginalFirstThunk ? pIm->OriginalFirstThunk : pIm->FirstThunk;
  69.             if (dwThunkData == 0)
  70.             {
  71.                 return ;
  72.             }
  73.             PIMAGE_THUNK_DATA pThunkData = (PIMAGE_THUNK_DATA)(dwThunkData + IMAGEBASE);
  74.             DWORD* pPfn = (DWORD*)(pIm->FirstThunk + IMAGEBASE);
  75.             while (pThunkData->u1.AddressOfData)
  76.             {
  77.                 FARPROC farProc = 0;
  78.                 LPCSTR lpParam2 = 0;
  79.                 // 最高位判断
  80.                 if (pThunkData->u1.AddressOfData & 0x80000000)
  81.                 {
  82.                     // 序号
  83.                     lpParam2 = LPCSTR(LOWORD(pThunkData->u1.AddressOfData));
  84.                 }
  85.                 else
  86.                 {
  87.                     // 函数名
  88.                     lpParam2 = LPCSTR(pThunkData->u1.AddressOfData + IMAGEBASE + 2);
  89.                 }
  90.                 farProc = GetProcAddress(hModule, lpParam2);
  91.                 // 填充IAT
  92.                 *pPfn = (DWORD)farProc;
  93.                 pThunkData++;
  94.                 pPfn++;
  95.             }
  96.             pIm++;
  97.         }
  98.     }
  99.     //取消映射
  100.     UnmapViewOfFile(pView);
  101.     //关闭文件映射对象
  102.     CloseHandle(hFileMap);
  103.     //关闭文件
  104.     CloseHandle(hFile);
  105. }
  106. int main()
  107. {
  108.     LoadPe();
  109.     if (g_oep != 0)
  110.     {
  111.         __asm
  112.         {
  113.             jmp g_oep;
  114.         }
  115.     }
  116.     return 0;
  117. }
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册