PE代码二次编写经验及过程 - 【加密与解密实验】

本文介绍了如何将一个用Delphi编写的简单程序进行二次开发,通过VC创建DLL并添加功能。利用LordPE在原程序的输入表中添加DLL函数,并使用ResScope添加菜单项,深入探讨了PE文件的修改与增强。
摘要由CSDN通过智能技术生成

1.首先我们看看最原始的程序,我们之后要做的工作就是将他的功能进行拓展。
nap2.jpg 
上面这个是使用Delphi编译的一个简单程序。
2.我们使用VC来编写一个DLL,写入主循环。

 

// lvusyy.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include <COMMDLG.H>
#include <WINDOWS.H>
#pragma comment(lib,"comdlg32")  //必须包含lib
//BOOL  OpenMenuS(HWND hWnd);
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                                         )
{
        
    return TRUE;
}

BOOL _stdcall  OpenMenuS(HWND hWnd)
{
        char filename[513]={'\0'};
        DWORD dw=0;
        char buf[65536]={'\0'}; //可以动态申请内存....  
        OPENFILENAME opfn;
        ZeroMemory(&opfn,sizeof(opfn));//使用前清空内存
        opfn.lStructSize=sizeof(opfn);//结构体的大小
        opfn.Flags=OFN_FILEMUSTEXIST; //标志
        opfn.lpstrFilter="Text File(*.txt)\0*.txt\0\0"; //过滤器
        opfn.lpstrFile=filename;//返回的文件全路径
        opfn.nMaxFile=512;//最大长度

        if(!GetOpenFileName(&opfn)) //  获得打开的文件名
        {
                return 0;
        }
        HANDLE hfile=CreateFile(filename,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); // 在内存当中映射文件
        if (GetLastError()) // 如果发生错误
        {
                MessageBox(NULL,"CreateFileERRER","ERRER",MB_ICONERROR);
                return 0;
        }
        if (!ReadFile(hfile,buf,65535,&dw,0))        // 读取文件
        {        CloseHandle(hfile);
                MessageBox(NULL,"ReadFileErr","ERRER",MB_ICONERROR);
                return 0;
        }
        CloseHandle(hfile);
        if(!SetWindowText(hWnd,buf)) // 设置
        {
                MessageBox(NULL,"SetWindowTextERR","ERRER",MB_ICONERROR);
                return 0;
        }
        return 1;
}
BOOL _stdcall SaveMenuS(HWND hWnd)
{        char buf[65536]={'\0'};
        OPENFILENAME opfm;
        char path[260]={'\0'};
        ZeroMemory(&opfm,sizeof(opfm));
        opfm.lStructSize=sizeof(opfm);
        opfm.Flags=OFN_FILEMUSTEXIST;
        opfm.lpstrDefExt=".Txt"; //这个是如果没输入后缀 程序会自动添加".txt"上去
        opfm.lpstrFilter="Text File(*.txt)\0*.txt\0\0";
        opfm.lpstrFile=path;
        opfm.nMaxFile=259;
        DWORD dw=0;
        if (!GetSaveFileName(&opfm))
        {
                return 0;
        }
        HANDLE hfile=CreateFile(path,GENERIC_WRITE,FILE_SHARE_WRITE,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
        if (GetLastError())
        {
                return 0;
        }
         GetWindowText(hWnd,buf,65535);
        if(strlen(buf)<1)
        {        CloseHandle(hfile);
                 MessageBox(0,"获取编辑框内容失败!",0,MB_ICONERROR);
                return 0;
        }
        if(!WriteFile(hfile,buf,65535,&dw,0))
        {CloseHandle(hfile);
         MessageBox(0,"写入文件失败!",0,MB_ICONERROR);
                return 0;
        }
CloseHandle(hfile);
        return 1;
}

BOOL _stdcall AboutBoxS()
{
                 MessageBox(0,"获取编辑框内容失败!",0,MB_ICONERROR);
             return 1;
}


然后DEF文件写上要导出的函数名称:

 

LIBRARY "lvusyy" // DLL库名称
EXPORTS // 导出函数
OpenMenuS @1
SaveMenuS @2
AboutBoxS @3


之后编译过后产生Lvusyy.dll文件,使用LordPE查看刚才使用Delphi编译的程序,在输入表当中添加DLL函数。
nap3.jpg 
nap4.jpg 
nap5.jpg 
之后我们使用ResScope给原程序添加两个菜单项目。
nap6.jpg 
nap7.jpg 

nap8.jpg 
将图中所示文字NOP掉,得到几段空白地址。
nap9.jpg 
nap11.jpg 
00401204   . /EB 56         JMP SHORT Pediy_Ch.0040125C
00401206   . |EB 1A         JMP SHORT Pediy_Ch.00401222

这两句是转向0040125C和401222地址的语句,我们跳转到所示的语句。


nap12.jpg

这里我详细解释一下这些语句的意思:

 
0040125C   > \817D F8 729C0>CMP DWORD PTR SS:[EBP-8],9C72
00401263   .  90            NOP
00401264   .  74 24         JE SHORT Pediy_Ch.0040128A
00401266   .  817D F8 739C0>CMP DWORD PTR SS:[EBP-8],9C73
0040126D   .  90            NOP
0040126E   .  74 3F         JE SHORT Pediy_Ch.004012AF
00401270   .  817D F8 539C0>CMP DWORD PTR SS:[EBP-8],9C53
00401277   .  90            NOP
00401278   .^ 74 8E         JE SHORT Pediy_Ch.00401208
0040127A   .  817D F8 459C0>CMP DWORD PTR SS:[EBP-8],9C45
00401281   .  90            NOP
00401282   .^ 74 A0         JE SHORT Pediy_Ch.00401224
00401284   .^ EB C0         JMP SHORT Pediy_Ch.00401246

第一句,是响应菜单编号为9752的,也就是说菜单编号为9C72的按下的时候,会执行
00401264   . /74 24         JE SHORT Pediy_Ch.0040128A

这一句其实就是OpenMenu的函数跳转
nap15.jpg
我们看看9C72翻译成十进制就是40050,其实就是我们刚才使用ResScope添加的菜单编号。
0040128A   > \60            PUSHAD
0040128B   .  FF35 60304000 PUSH DWORD PTR DS:[403060]
00401291   .  FF15 52504000 CALL DWORD PTR DS:[<&lvusyy.OpenMenuS>]  ;  lvusyy.OpenMenuS
00401297   .  61            POPAD
00401298   >^ EB AC         JMP SHORT Pediy_Ch.00401246

这里 PUSH AD,是将参数压入栈,这个参数实质上就是编辑框的句柄。
0040128B . FF35 60304000 PUSH DWORD PTR DS:[403060]

这句,是将DS寄存器,偏移为403060所在的双字压入栈当中。
我们函数在实行的时候,编译器首先会将参数从右至左依次入栈,然后给程序调用。
我们看看403060是在哪里出现的吧:
nap16.jpg
00401173   > \6A 00         PUSH 0                                   ; /lParam = NULL
00401175   .  8B4D 14       MOV ECX,DWORD PTR SS:[EBP+14]            ; |
00401178   .  8B51 04       MOV EDX,DWORD PTR DS:[ECX+4]             ; |
0040117B   .  52            PUSH EDX                                 ; |hInst
0040117C   .  6A 01         PUSH 1                                   ; |hMenu = 00000001
0040117E   .  8B45 08       MOV EAX,DWORD PTR SS:[EBP+8]             ; |
00401181   .  50            PUSH EAX                                 ; |hParent
00401182   .  6A 00         PUSH 0                                   ; |Height = 0
00401184   .  6A 00         PUSH 0                                   ; |Width = 0
00401186   .  6A 00         PUSH 0                                   ; |Y = 0
00401188   .  6A 00         PUSH 0                                   ; |X = 0
0040118A   .  68 C400B050   PUSH 50B000C4                            ; |Style = WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL|WS_BORDER|C4
0040118F   .  6A 00         PUSH 0                                   ; |WindowName = NULL
00401191   .  68 3C304000   PUSH Pediy_Ch.0040303C                   ; |Class = "edit"
00401196   .  6A 00         PUSH 0                                   ; |ExtStyle = 0
00401198   .  FF15 1C204000 CALL DWORD PTR DS:[<&USER32.CreateWindow>; \CreateWindowExA
0040119E   .  A3 60304000   MOV DWORD PTR DS:[403060],EAX

这里很明显,使用API - Create WindowEXA创建了一个"edit"的编辑框,
0040119E . A3 60304000 MOV DWORD PTR DS:[403060],EAX

这一句,就是将编辑框的句柄压入EAX。

我们回到刚才菜单响应那里,看看
0040128A > \60 PUSHAD
0040128B . FF35 60304000 PUSH DWORD PTR DS:[403060]
00401291 . FF15 52504000 CALL DWORD PTR DS:[<&lvusyy.OpenMenuS>] ; lvusyy.OpenMenuS
00401297 . 61 POPAD
00401298 >^ EB AC JMP SHORT Pediy_Ch.00401246

最后一句。
00401298 >^ EB AC JMP SHORT Pediy_Ch.00401246
其实就是菜单执行完毕之后,返回主循环当中,使程序继续响应其他事件。
0040128A > \60 PUSHAD
0040128B . FF35 60304000 PUSH DWORD PTR DS:[403060]
00401291 . FF15 52504000 CALL DWORD PTR DS:[<&lvusyy.OpenMenuS>] ; lvusyy.OpenMenuS
00401297 . 61 POPAD
00401298 >^ EB AC JMP SHORT Pediy_Ch.00401246

我们其实可以将这一句:
00401291 . FF15 52504000 CALL DWORD PTR DS:[<&lvusyy.OpenMenuS>] ; lvusyy.OpenMenuS

看做是函数调用,这一句调用的便是我们DLL当中的OpenMenuS函数,只不过参数已经被上面压入栈了。
修改之后的程序就成了:
nap17.jpg
nap18.jpg
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值