吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8734|回复: 24
收起左侧

[游戏安全] 【原创】CE自写插件提供LUA接口实现pvz僵尸绘制之下篇

  [复制链接]
lyl610abc 发表于 2021-2-11 16:01
本帖最后由 lyl610abc 于 2021-2-11 16:08 编辑

前言:

承接上篇教程,这次来讲讲如何为CE开发扩展的插件

上篇教程直达车:CE自写插件提供LUA接口实现pvz僵尸绘制之上篇


总教程分成两部分:

  • LUA的使用
  • Plugin的开发

本下篇教程为Plugin的开发部分

事前准备

本人使用的工具:CE7.2汉化版(这次要注意版本,插件和CE版本相关,汉化与否不影响)

论坛有:CE7.2

VS2015 (可以兼容XP的插件开发)

VS2015:https://my.visualstudio.com/Downloads?q=visual%20studio%202015&wt.mc_id=o~msft~vscom~older-downloads

CE7.2源码一份:https://github.com/cheat-engine/cheat-engine/archive/7.2.zip

教程内容

VS2015的安装

插件编译环境

CE插件的编译中 example-c里使用的环境是VS2015+WDK8.1(能够兼容XP)

image-20210210183952985

根据我上面提供的链接下载并安装VS2015 (貌似下载前要登陆Microsoft账号)

image-20210210183416917

下载和安装VS2015的教程网上很多,这里不作重点,默认大家能安装好了

PS:安装好后用VS2015打开Plugin插件

Plugin 源码解析

想知道如何开发一个插件,必不可少的就是去读一读别人的源码

下载并解压源码以后切换到\cheat-engine-7.2\Cheat Engine\plugin\example-c目录下

image-20210210190512849

用VS2015打开.sln文件(如果是第一次打开会让你下载WDK8.1等相关的组件,点击确定让它自动下载安装即可)

image-20210210190706747

源码结构

image-20210210190934311

首先明确一点:我们编写出来的插件是dll格式,即是开发一个动态链接库程序作为插件给CE调用

我们可以大致将这个例子的结构分为四层

结构 包含文件
一个全被注释的头文件和一个空的源文件,留给我们拓展用的,可以删去 bla.h bla.cpp
CE提供给我们的头文件和LUA提供给我们的头文件 cepluginsdk.h lauxlib.h lua.h luaconf.h lualib.h
主程序代码,即我们要编写插件的关键代码 example-c
定义我们要导出的函数 example-c.def

需要用到的静态库文件

我们看到了头文件里有LUA和CE提供的头文件,但源文件里并没有对应的源文件,于是我们知道是引入了.lib静态库文件

那么静态库文件在哪呢?

项目→属性→链接器→输入→附加依赖项

image-20210210192559410

image-20210210192643755

将上方的平台分别改为Win32和X64,可以看到附加依赖项分别显示为:

image-20210210192729562

image-20210210192750875

我们可以知道该项目使用了lua53-32.lib和lua53-64.lib

image-20210210192949570

这两个lib文件就在cheat-engine-7.2\Cheat Engine\plugin目录下

我们可以将这两个.lib文件复制到cheat-engine-7.2\Cheat Engine\plugin\example-c中

下面简单说一下.lib文件的来源,我们也可以自己生成这两个.lib文件

编译lib静态库文件(非必须)

cheat-engine-7.2\Cheat Engine\lua53\lua53\vs2013\lua53目录下自己编译.lib静态库文件

image-20210210193527486

image-20210210193720043

生成lua53-64.lib

打开项目以后需要设置一下项目的属性

将lua53的平台工具集改为Visual Studio 2015 - Windows XP (v140_xp)

平台改为x64

image-20210210194051711

然后打开配置管理器,将活动解决方案配置改为Release,活动解决方案平台改成x64

image-20210210194421050

然后Ctrl+Shift+B或者生成→生成解决方案

image-20210210194602657

可以看到我们所需要的静态库文件生成在了cheat-engine-7.2\Cheat Engine\bin下

image-20210210195004287

我图中用红框框出来的就是我们刚刚生成的文件,其中我们只需要用到.lib文件

生成lua53-32.lib

将之前的属性页和配置管理器页中的平台改成Win32,再生成一份lua53-32

image-20210210195218993

image-20210210195239192

image-20210210195444569

image-20210210195533901

编译example-c插件

拿到源码以后最想干的事莫过于先让它跑起来,验证是否能够正确运行,于是我们先将插件编译出来再慢慢分析

将前面我们生成好的(或者直接拿上级目录里的)lua53-32.lib和lua53-64.lib复制到cheat-engine-7.2\Cheat Engine\plugin\example-c下

复制完以后打开example-c这个项目

然后确保将配置管理器改成 Release和x64

属性页设置为所有平台

image-20210210202752883

image-20210210202845467

设置完以后就可以Ctrl+Shift+B编译插件了

image-20210210205119056

完美生成插件

在cheat-engine-7.2\Cheat Engine\plugin\example-c\x64\Release查看

image-20210210205436686

我们试着用CE加载一下插件

打开CE→编辑→设置→插件→添加

image-20210210205838298

image-20210210205852327

image-20210210205901681

源码解析

导出函数说明

我们先看.def文件,查看导出的函数

image-20210210211548799

有三个导出的函数:

分别为:CEPlugin_GetVersion        CEPlugin_InitializePlugin        CEPlugin_DisablePlugin


我们可以看看有关CE插件的文档:https://cheatengine.org/help/index.html

Cheat Engine comes with a plugin system so developers can add extra functions and features to ce without having to code in Delphi (Any language that can create standard DLL's with normal exports can make plugins for ce), or having to share their sourcecode.

CE 带来了插件系统 这样一来开发者们就可以添加额外的功能和特性到CE里,无需用Delphi 编程(任何语言都可以为CE创建正常导出的标准的DLL)

To make use of the plugin system you need to create a dll that exports 3 functions:

为了确保插件系统的正常运转,你需要创建一个带有以下三个导出功能的dll

GetVersion, DisablePlugin, and InitializePlugin

Note: Unless stated otherwise, all function calls use the stdcall calling mechanism.

注意:除非额外声明,所有的功能调用协定都应该使用stdcall

Cheat Engine comes with some example plugins. They generally make use of a common SDK file. Currently, there is a version for Delphi and a version for C available

CE带来了一些例子插件。它们通常使用一个公共的SDK文件,目前,有一个Delphi版本和一个C版本


所以我们知道为什么导出的函数里有这三个函数了

依次说说这三个函数

GetVersion

The GetVersion routine is a routine that will get called when the dll is queried for the first time.

GetVersion例程是第一次查询dll时将调用的例程

BOOL GetVersion(

PPluginVersion pv,             //pointer to structure you have to fill in

int sizeofpluginversion            //size of pluginversion

);
参数 参数类型 说明
pv PPluginVersion 指向PluginVersion的指针,必须填充
sizeofpluginversion int pv参数中提供的PluginVersion结构的大小。您可以使用这个来确保您的插件版本与作弊引擎插件系统的当前实现兼容。目前,应该是8
返回值 返回值类型 说明
true bool 返回值必须设置为1
PluginVersion

The PluginVersion lets you specify for which plugin version the dll was developed and what the name of that plugin is.

PluginVersion允许你指定插件版本以及该插件的名称

typedef struct _PluginVersion

{

 unsigned int version;

 char *pluginname;

} PluginVersion, *PPluginVersion;
成员 属性 说明
version unsigned int(无符号整型) 设置这个dll所期望的版本
pluginname char *(字符串) CE会在initializePlugin上为你的插件提供一个兼容的指针/函数列表。
DisablePlugin
BOOL DisablePlugin(void)

The DisablePlugin routine is a routine that will get called when Cheat Engine closes or when the user deselects the plugin in settings.

DisablePlugin例程,当CE关闭或用户在设置中取消选择插件时,它将被调用。

返回值 返回值类型 说明
true bool 返回值必须设置为1
InitializePlugin

The InitializePlugin routine is called when Cheat Engine is started and the plugin is enabled in the registry, or when the user enables it in settings and clicks ok.

当启动CE并在注册表中启用插件时,或者当用户在“设置”中启用插件并单击“确定”时,将调用InitializePlugin例程。

BOOL InitializePlugin(
PExportedFunctions ef ,
int pluginid
);
参数 参数类型 说明
ef PExportedFunctions CE的ExportedFunctions结构的地址副本,在从InitializePlugin函数返回之前复制此结构
pluginid int 插件id,只要你的插件处于活动状态,它的pluginid就一直存在。此ID用于注册回调
返回值 返回值类型 说明
true bool 返回值必须设置为1

It is recommended to register the callback functions in this routine and save ExportedFunctions for later usage. For more information about the callbacks see the relevant help topics

建议在此例程中注册回调函数,并保存ExportedFunctions以备以后使用。有关回调的更多信息,请参阅相关的帮助主题

ExportedFunctions

The ExportedFunctions structure contains several pointers to usefull functions in CE, and pointers to the pointers of specific functions that might be worth hooking.

ExportedFunctions结构包含几个指向CE中有用函数的指针,以及指向可能值得hook的特定函数的指针。

typedef struct _ExportedFunctions
{
  int sizeofExportedFunctions;
  CEP_SHOWMESSAGE ShowMessage;
  CEP_REGISTERFUNCTION RegisterFunction;
  CEP_UNREGISTERFUNCTION UnregisterFunction ;
  PULONG OpenedProcessID ;
  PHANDLE OpenedProcessHandle ;

  CEP_GETMAINWINDOWHANDLE GetMainWindowHandle;
  CEP_AUTOASSEMBLE AutoAssemble;
  CEP_ASSEMBLER Assembler;
  CEP_DISASSEMBLER Disassembler ;
  CEP_CHANGEREGATADDRESS ChangeRegistersAtAddress ;
  CEP_INJECTDLL InjectDLL ;
  CEP_FREEZEMEM FreezeMem;
  CEP_UNFREEZEMEM UnfreezeMem;
  CEP_FIXMEM FixMem;
  CEP_PROCESSLIST ProcessList;
  CEP_RELOADSETTINGS ReloadSettings;
  CEP_GETADDRESSFROMPOINTER GetAddressFromPointer ;

  //pointers to the address that contains the pointers to the functions
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  PVOID ReadProcessMemory;                
  PVOID WriteProcessMemory;               
  PVOID GetThreadContext;                 
  PVOID SetThreadContext;                 
  PVOID SuspendThread;                    
  PVOID ResumeThread;                     
  PVOID OpenProcess;                      
  PVOID WaitForDebugEvent;                
  PVOID ContinueDebugEvent;               
  PVOID DebugActiveProcess;               
  PVOID StopDebugging;                    
  PVOID StopRegisterChange;               
  PVOID VirtualProtect;                   
  PVOID VirtualProtectEx;                 
  PVOID VirtualQueryEx;                   
  PVOID VirtualAllocEx;                   
  PVOID CreateRemoteThread;               
  PVOID OpenThread;                       
  PVOID GetPEProcess;                     
  PVOID GetPEThread;                      
  PVOID GetThreadsProcessOffset;    
  PVOID GetThreadListEntryOffset;   
  PVOID GetProcessnameOffset;       
  PVOID GetDebugportOffset;         
  PVOID GetPhysicalAddress;         
  PVOID ProtectMe;                  
  PVOID GetCR4;                     
  PVOID GetCR3;                     
  PVOID SetCR3;                     
  PVOID GetSDT;                     
  PVOID GetSDTShadow;               
  PVOID setAlternateDebugMethod;    
  PVOID getAlternateDebugMethod;    
  PVOID DebugProcess;               
  PVOID ChangeRegOnBP;              
  PVOID RetrieveDebugData;          
  PVOID StartProcessWatch;          
  PVOID WaitForProcessListData;     
  PVOID GetProcessNameFromID;       
  PVOID GetProcessNameFromPEProcess;
  PVOID KernelOpenProcess;          
  PVOID KernelReadProcessMemory;    
  PVOID KernelWriteProcessMemory;   
  PVOID KernelVirtualAllocEx;       
  PVOID IsValidHandle;              
  PVOID GetIDTCurrentThread;        
  PVOID GetIDTs;                    
  PVOID MakeWritable;               
  PVOID GetLoadedState;             
  PVOID DBKSuspendThread;           
  PVOID DBKResumeThread;            
  PVOID DBKSuspendProcess;          
  PVOID DBKResumeProcess;           
  PVOID KernelAlloc;                
  PVOID GetKProcAddress;            
  PVOID CreateToolhelp32Snapshot;   
  PVOID Process32First;             
  PVOID Process32Next;              
  PVOID Thread32First;              
  PVOID Thread32Next;               
  PVOID Module32First;              
  PVOID Module32Next;               
  PVOID Heap32ListFirst;            
  PVOID Heap32ListNext;             
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  PVOID mainform;
  PVOID memorybrowser;

  CEP_GENERATEAPIHOOKSCRIPT sym_nameToAddress;
  CEP_ADDRESSTONAME sym_addressToName ;
  CEP_NAMETOADDRESS sym_generateAPIHookScript;

  CEP_LOADDBK32 loadDBK32;
  CEP_LOADDBVMIFNEEDED loaddbvmifneeded;
  CEP_PREVIOUSOPCODE previousOpcode;
  CEP_NEXTOPCODE nextOpcode;
  CEP_DISASSEMBLEEX disassembleEx;
  CEP_LOADMODULE loadModule;
  CEP_AA_ADDCOMMAND aa_AddExtraCommand;
  CEP_AA_DELCOMMAND aa_RemoveExtraCommand;

  CEP_CREATETABLEENTRY createTableEntry;
  CEP_GETTABLEENTRY getTableEntry;
  CEP_MEMREC_SETDESCRIPTION memrec_setDescription;
  CEP_MEMREC_GETDESCRIPTION memrec_getDescription;
  CEP_MEMREC_GETADDRESS memrec_getAddress;
  CEP_MEMREC_SETADDRESS memrec_setAddress;
  CEP_MEMREC_GETTYPE memrec_getType;
  CEP_MEMREC_SETTYPE memrec_setType;
  CEP_MEMREC_GETVALUETYPE memrec_getValue;
  CEP_MEMREC_SETVALUETYPE memrec_setValue;
  CEP_MEMREC_GETSCRIPT memrec_getScript;
  CEP_MEMREC_SETSCRIPT memrec_setScript;
  CEP_MEMREC_ISFROZEN memrec_isfrozen;
  CEP_MEMREC_FREEZE memrec_freeze;
  CEP_MEMREC_UNFREEZE memrec_unfreeze;
  CEP_MEMREC_SETCOLOR memrec_setColor;
  CEP_MEMREC_APPENDTOENTRY memrec_appendtoentry;
  CEP_MEMREC_DELETE memrec_delete;

  CEP_GETPROCESSIDFROMPROCESSNAME getProcessIDFromProcessName;
  CEP_OPENPROCESS openProcessEx;
  CEP_DEBUGPROCESS debugProcessEx;
  CEP_PAUSE pause;
  CEP_UNPAUSE unpause;

  CEP_DEBUG_SETBREAKPOINT debug_setBreakpoint;
  CEP_DEBUG_REMOVEBREAKPOINT debug_removeBreakpoint;
  CEP_DEBUG_CONTINUEFROMBREAKPOINT debug_continueFromBreakpoint;

  CEP_CLOSECE closeCE;
  CEP_HIDEALLCEWINDOWS hideAllCEWindows;
  CEP_UNHIDEMAINCEWINDOW unhideMainCEwindow;
  CEP_CREATEFORM createForm;
  CEP_FORM_CENTERSCREEN form_centerScreen;
  CEP_FORM_HIDE form_hide;
  CEP_FORM_SHOW form_show;
  CEP_FORM_ONCLOSE form_onClose;

  CEP_CREATEPANEL createPanel;
  CEP_CREATEGROUPBOX createGroupBox;
  CEP_CREATEBUTTON createButton;
  CEP_CREATEIMAGE createImage;
  CEP_IMAGE_LOADIMAGEFROMFILE image_loadImageFromFile;
  CEP_IMAGE_TRANSPARENT image_transparent;
  CEP_IMAGE_STRETCH image_stretch;

  CEP_CREATELABEL createLabel;
  CEP_CREATEEDIT createEdit;
  CEP_CREATEMEMO createMemo;
  CEP_CREATETIMER createTimer;
  CEP_TIMER_SETINTERVAL timer_setInterval;
  CEP_TIMER_ONTIMER timer_onTimer;
  CEP_CONTROL_SETCAPTION control_setCaption;
  CEP_CONTROL_GETCAPTION control_getCaption;
  CEP_CONTROL_SETPOSITION control_setPosition;
  CEP_CONTROL_GETX control_getX;
  CEP_CONTROL_GETY control_getY;
  CEP_CONTROL_SETSIZE control_setSize;
  CEP_CONTROL_GETWIDTH control_getWidth;
  CEP_CONTROL_GETHEIGHT control_getHeight;
  CEP_CONTROL_SETALIGN control_setAlign;
  CEP_CONTROL_ONCLICK control_onClick;

  CEP_OBJECT_DESTROY object_destroy;
  CEP_MESSAGEDIALOG messageDialog;
  CEP_SPEEDHACK_SETSPEED speedhack_setSpeed; 

} ExportedFunctions, *PExportedFunctions;

这个函数的成员太多了,具体的可以自己去看参考文档QAQ

导出函数具体分析
CEPlugin_GetVersion
BOOL __stdcall CEPlugin_GetVersion(PPluginVersion pv , int sizeofpluginversion)
{
        pv->version=CESDK_VERSION;        //这里的CESDK_VERSION为常量6,可以自行修改
        pv->pluginname="C Example v1.3 (SDK version 4: 6.0+)"; //像这样的精确字符串是指向dll中的字符串的指针,因此是可行的
        return TRUE;
}
CEPlugin_DisablePlugin
BOOL __stdcall CEPlugin_DisablePlugin(void)
{
        //调用MessageBoxA方法弹窗,表示当前插件已关闭
        MessageBoxA(0,"disabled plugin","Example C plugin", MB_OK);

        return TRUE;
}
CEPlugin_InitializePlugin
BOOL __stdcall CEPlugin_InitializePlugin(PExportedFunctions ef , int pluginid)
{
    //中间省略的部分为在CE的窗口中添加自己的菜单等界面的功能,暂时没有用到,有兴趣的可以自己研究
        //....省略//
        selfid=pluginid;
        //....省略//
        lua_State *lua_state=ef->GetLuaState();        //这里的lua_state固定写成这样就好
    //注册lua的调用事件,这个是lua提供的函数        
    //这里的lua_pluginExample是我们按照LUA规范定义的C语言函数,提供给LUA调用,下面会具体讲解
        lua_register(lua_state, "pluginExample", lua_pluginExample);

        Exported.ShowMessage("The \"Example C\" plugin got enabled");
        return TRUE;
}

关于lua的函数可以参考Lua 函数索引,这里只讲解用到的

lua_register

参考lua_register

void lua_register (lua_State *L, const char *name, lua_CFunction f);

把 C 函数 f 设到全局变量 name 中。 它通过一个宏定义:

     #define lua_register(L,n,f) \
            (lua_pushcfunction(L, f), lua_setglobal(L, n))

这里可以知道其实lua_register其实是在调用lua_pushcfunction和lua_setglobal

lua_pushcfunction
void lua_pushcfunction (lua_State *L, lua_CFunction f);

参考lua_pushcfunction

将一个 C 函数压栈。 这个函数接收一个 C 函数指针, 并将一个类型为 function 的 Lua 值压栈。 当这个栈顶的值被调用时,将触发对应的 C 函数。

注册到 Lua 中的任何函数都必须遵循正确的协议来接收参数和返回值 (参见 lua_CFunction

lua_CFunction
typedef int (*lua_CFunction) (lua_State *L);

定义了要在LUA中调用的C函数的格式,下面看看example-c中的范例

lua_pluginExample
int lua_pluginExample(lua_State *L) //make sure this is cdecl        确保采用默认的cdecl调用协定
{
        Exported.ShowMessage("Called from lua");//CE中输出消息
        lua_pushinteger(L, 123);//将123作为返回值压入到堆栈中
        return 1;//返回 返回值的个数,这里只有一个返回值123
}

C 函数只需要把它们以正序压到堆栈上(第一个返回值最先压入), 然后返回这些返回值的个数

Lua和C/C++语言通信的主要方法是一个无处不在的虚拟栈

lua_setglobal

参考lua_setglobal

void lua_setglobal (lua_State *L, const char *name);

从堆栈上弹出一个值,并将其设为全局变量 name 的新值


综上分析我们可以得知lua_register的信息

参数 参数类型 含义
L lua_State* 指向lua_State的指针,这里我们固定赋值为ef->GetLuaState()即可
name const char * 在lua中要调用时的函数名称
f lua_CFunction 遵循正确的lua协议的C函数
返回值 返回值类型 说明
num int 返回前面压入到堆栈中的个数

在CE LUA中调用插件提供的函数

上面给大家讲解了我们插件的源码以及插件中提供的LUA的接口,接下来演示在CE的LUA中调用函数

首先确保加载了example-c插件

可以看到后面的此时插件显示的面板为CEPlugin_GetVersion中我们设置的内容

image-20210211131605923

然后打开LUA窗口:表单→显示CT表的Lua脚本

image-20210211132001336

我们输入lua命令来调用CEPlugin_InitializePlugin中通过lua_register注册的函数

ret=pluginExample()        --这里的pluginExample是在lua_register中注册的第二个参数
print(ret)                        --这里的返回值是lua_pushinteger得来的

执行以后可以看到:

image-20210211132140107

image-20210211132204487

调用了我们在C中定义好的函数

开发自己的CE Plugin

前面分析完了CE自带的插件例子,我们开始着手自己写一个插件吧

创建项目

打开VS2015        文件→新建→项目        (Ctrl+Shift+N)

image-20210211143036501

点击确定以后出现Win32 应用程序向导

image-20210211143115494

image-20210211143613774

完成以后,一个空的DLL项目就出现了

image-20210211143847108

设置项目属性

我们点击源文件,右键 添加→新建项 (Ctrl+Shift+A)

image-20210211143927942

image-20210211144042090

创建出一个空的main.cpp以后,我们设置一下项目的属性:项目→属性

image-20210211144146837

image-20210211144218992

确保配置为Release 平台为所有平台

然后打开配置管理器,同样修改配置和平台

image-20210211144313016

导入CE相关文件

接下来别忘了导入CE提供的 .lib文件以及.h头文件

将cheat-engine-7.2\Cheat Engine\plugin下的以下文件复制到我们项目的目录下

image-20210211150935139

image-20210211151032944

然后回到VS2015,选中项目 右键 添加→现有项

image-20210211151150372

将我们之前复制的文件全部添加进来

image-20210211151229766

此时.h头文件已经添加进来可以使用了,但静态库.lib文件还需要添加一下引用

项目→属性→链接器→输入→附加依赖项→编辑

image-20210211151637978

然后将lua53-32.lib和lua53-64.lib添加进来

image-20210211151718726

添加完成后显示为image-20210211151801331

PS:也可以在代码的开头添加下列代码来引入静态库文件

#pragma comment(lib,"lua53-32.lib")
#pragma comment(lib,"lua53-64.lib")

添加DLL入口函数

这个是DLL函数必须的入口函数,可以从example-c那里拷贝过来,开发DLL的基础~~~

BOOL APIENTRY DllMain(HANDLE hModule,
        DWORD  ul_reason_for_call,
        LPVOID lpReserved
)
{
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
                //MessageBox(0,"This plugin dll got loaded (This message comes from the dll)","C Plugin Example",MB_OK);
                break;

        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
                break;
        }

        return TRUE;
}

添加.del导出配置

在源文件这里 右键 新建→新建项

image-20210211152717446

image-20210211152659630

在.def文件中写如以下内容

LIBRARY        MyPlugin
EXPORTS   
    CEPlugin_GetVersion        @1
    CEPlugin_InitializePlugin @2
    CEPlugin_DisablePlugin @3

表明以上三个函数为要的导出函数,原因之前已经说过是CE规范要求的

编写自己的功能

接着就在我们的程序中分别添加这三个函数即可

#include <windows.h>
#include <stdio.h>
#include "cepluginsdk.h"
//导入静态库
#pragma comment(lib,"lua53-32.lib")
#pragma comment(lib,"lua53-64.lib")

//插件的id
int selfid;

//CE 提供的导出功能
ExportedFunctions Exported;

//入口函数
BOOL APIENTRY DllMain(HANDLE hModule,
        DWORD  ul_reason_for_call,
        LPVOID lpReserved
)
{
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
                //MessageBox(0,"This plugin dll got loaded (This message comes from the dll)","C Plugin Example",MB_OK);
                break;

        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
                break;
        }

        return TRUE;
}

BOOL __stdcall CEPlugin_GetVersion(PPluginVersion pv , int sizeofpluginversion)
{
        pv->version=CESDK_VERSION;        //这里的CESDK_VERSION为常量6,可以自行修改
        pv->pluginname="MyPlugin"; //像这样的精确字符串是指向dll中的字符串的指针,因此是可行的
        return TRUE;
}

//满足LUA规范的C函数,这里为调用WIN32的GetWindowRect函数并返回
int __cdecl lua_GetWindowRect(lua_State *L) //make sure this is cdecl
{
        DWORD handle = luaL_checknumber(L, 1);
        //Exported.ShowMessage("Called from lua");
        RECT rect;
        ZeroMemory(&rect, sizeof(RECT));
        GetWindowRect((HWND)handle, &rect);
        //lua_pushinteger(L, handle);
        lua_pushinteger(L, rect.left);
        lua_pushinteger(L, rect.top);
        lua_pushinteger(L, rect.right);
        lua_pushinteger(L, rect.bottom);
        return 4;
}

BOOL __stdcall CEPlugin_InitializePlugin(PExportedFunctions ef, int pluginid)
{

        selfid = pluginid;

        //copy the EF list to Exported
        Exported = *ef; //Exported is defined in the .h
        if (Exported.sizeofExportedFunctions != sizeof(Exported))
                return FALSE;

        lua_State *lua_state = ef->GetLuaState();
        //注册lua的调用事件,这个是lua提供的函数        
    //这里的lua_GetWindowRect是我们按照LUA规范定义的C语言函数,提供给LUA调用
        lua_register(lua_state, "GetWindowRect", lua_GetWindowRect);

        Exported.ShowMessage("The \"MyPlugin\" plugin got enabled");
        return TRUE;
}

BOOL __stdcall CEPlugin_DisablePlugin(void)
{
        //clean up memory you might have allocated
        MessageBoxA(0, "disabled plugin", "MyPlugin", MB_OK);

        return TRUE;
}

测试自己的功能

然后我们Ctrl+Shift+B编译我们的插件

image-20210211153852967

将生成好的插件用CE加载

image-20210211153810924

image-20210211153933659

image-20210211153954199

image-20210211154015117

image-20210211154201166

image-20210211154207493

测试完毕!!!我们的函数可以正常调用,否则原本会显示

image-20210211154352286

image-20210211154412069

总结

总算是把这个教程给更新完了,CE的插件功能可以让我们用C来实现很多强大的功能,我只是简单地带大家了解了一下有关CE的插件开发流程,还可以增加很多有用复杂的功能,我这里限于篇幅也不展开了。底下会附上我开发的插件的源码和插件

最后,希望大家能一起变强,相互交流,相互进步,我也只是个勉强入门的萌新,能力不足,水平有限,希望大家多多支持和鼓励一下。以上~~~~期待我们的下次再会

下载链接:MyPlugin

源码太大了,只能用自己的阿里云OSS了 QAQ

PS:本插件和上篇教程的插件是同一个插件,改了个名字而已

免费评分

参与人数 9威望 +1 吾爱币 +30 热心值 +9 收起 理由
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
_小白 + 1 + 1 我很赞同!
遛你玩528 + 1 + 1 感谢楼主无私分享
dian01 + 1 + 1 大年初一来顶贴!原来CE还能这样玩
qaz003 + 1 + 1 大年三十顶一个
剑圣戏金莲 + 1 + 1 我很赞同!
fanvalen + 1 + 1 不错的lua
某中二绅士 + 3 + 1 用心讨论,共获提升!
国际豆哥 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| lyl610abc 发表于 2021-2-11 16:02
预留楼层,等待更新
 楼主| lyl610abc 发表于 2021-2-11 23:31
本帖最后由 lyl610abc 于 2021-2-11 23:33 编辑
会飘的云 发表于 2021-2-11 23:26
就想问问 能 做到什么程度 或者说能做些什么?

C语言能做什么,插件就能做什么,这个插件就是提供C接口给CE调用。
也可以在CE里添加自己的菜单栏等等
就是拓展CE功能用的
具体一点的话,举个例子,比如可以在插件里写个过保护,让CE加载插件以后就过检测等等
会飘的云 发表于 2021-2-12 12:28
lyl610abc 发表于 2021-2-11 23:31
C语言能做什么,插件就能做什么,这个插件就是提供C接口给CE调用。
也可以在CE里添加自己的菜单栏等等
...

过保护 需要的知识就太多了,之前学过一段时间的驱动过保护,由于基础知识太浅学起来特吃力 后来放弃了
不苦小和尚 发表于 2021-2-11 16:33
好详细不错不错,谢谢分享
国际豆哥 发表于 2021-2-11 16:58
大佬加油我支持你的
uzbek_hit 发表于 2021-2-11 17:00
大佬啊,教程好详细
iigames 发表于 2021-2-11 17:26
学到了,教程好详细
天空の幻像 发表于 2021-2-11 20:29
大佬,厉害,学习了
国际豆哥 发表于 2021-2-11 22:19
lyl610abc 发表于 2021-2-11 16:02
预留楼层,等待更新

大佬大佬牛逼(破音)
tingfeng69 发表于 2021-2-11 22:28
好厉害啊,佩服
会飘的云 发表于 2021-2-11 23:26
lyl610abc 发表于 2021-2-11 16:02
预留楼层,等待更新

就想问问 能 做到什么程度 或者说能做些什么?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-22 01:23

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表