在《在windows程序中嵌入Lua脚本引擎--建立一个简易的“云命令”执行的系统》一文中,我提到了使用Lua的ffi库,可以让我们像写C代码一样写lua程序。这是个非常令我们这些C程序员激动的事。但是我们使用ffi库写出来的程序往往比较大,因为我们可能要声明一些API的原型和结构体。比如我们看luajit的wiki中关于使用ffi调用kernel32的一个例子。(转载请指明出于breaksoftware的csdn博客)如果我们要使用

BOOL HeapWalk(HANDLE hHeap, PROCESS_HEAP_ENTRY * lpEntry);

则在Lua中要做如下声明

ffi.cdef[[
typedef struct _PROCESS_HEAP_ENTRY {PVOID lpData;DWORD cbData;BYTE cbOverhead;BYTE iRegionIndex;WORD wFlags;union {struct {HANDLE hMem;DWORD dwReserved[ 3 ];} Block;struct {DWORD dwCommittedSize;DWORD dwUnCommittedSize;LPVOID lpFirstBlock;LPVOID lpLastBlock;} Region;} DUMMYUNIONNAME;
} PROCESS_HEAP_ENTRY, *LPPROCESS_HEAP_ENTRY, *PPROCESS_HEAP_ENTRY;BOOL HeapWalk(HANDLE hHeap, PROCESS_HEAP_ENTRY * lpEntry);
]]

即告诉Lua,我们要调用的函数的名字和函数使用的结构体的原型。

看到这,可能会让想使用ffi库的朋友打起了退堂鼓。那我们如何才可以比较简洁的调用这个函数呢?那就是:编写我们自己的Lua库"fl"。

我们可以参考luajit中os库的声明方式。

1 lualib.h中新增我们库的名字"fl",并声明注册我们库的函数luaopen_fl

……
#define LUA_FFILIBNAME  "ffi"
#define LUA_FLLIBNAME   "fl"
……
LUALIB_API int luaopen_ffi(lua_State *L);
LUALIB_API int luaopen_fl(lua_State *L);

2 在lib_init.c中,将我们的库名字和打开库的名字banding

……{ LUA_JITLIBNAME,  luaopen_jit },{ LUA_FLLIBNAME, luaopen_fl },{ NULL,     NULL }

3 在Lualib目录下新建一个lib_fl.c文件

实现最基本的函数和结构。主要是实现注册我们库的luaopen_fl函数,和函数名和函数地址绑定结构体数组uaL_Reg_fl_lib

#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_lib.h"
static const luaL_Reg fl_lib[] = {{ NULL, NULL }
};LUALIB_API int luaopen_fl(lua_State *L)
{luaL_register(L, LUA_FLLIBNAME, fl_lib);return 1;
}

4 将lib_fl.c加入《在windows程序中嵌入Lua脚本引擎--使用VS IDE编译Luajit脚本引擎》中介绍的Lua工程。
        5 修改《在windows程序中嵌入Lua脚本引擎--使用VS IDE编译Luajit脚本引擎》中介绍的Buildvm工程的生成后事件。在事件中,将lib_fl.c加入ALL_LIB中

@set ALL_LIB=lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c lib_fl.c

6 在ljamalg.c中新增#include "lib_fl.c"

如此我们便新增了一个名字叫fl的库,我们可以

fl = require "fl"
fl.……

这样调用它。

现在我们要扩充我的库:

A 在fl库中新增一个获取系统版本信息的函数

LJLIB_CF(fl_GetSystemVersion)
{OSVERSIONINFOA osver;ZeroMemory(&osver, sizeof(OSVERSIONINFOA));osver.dwOSVersionInfoSize = sizeof(osver);if ( GetVersionExA(&osver) ){lua_pushnumber(L, osver.dwMajorVersion);lua_pushnumber(L, osver.dwMinorVersion);lua_pushnumber(L, osver.dwBuildNumber);lua_pushnumber(L, osver.dwPlatformId);lua_pushstring(L, osver.szCSDVersion);return 5;}else{return 0;}
}

并在fl_lib数组中新增名字和该函数的地址的绑定

static const luaL_Reg fl_lib[] = {{ "GetSystemVersion",   lj_cf_fl_GetSystemVersion },{ NULL, NULL }
};

这样我们编译出来的luajit便可以使用简单的方法调用获取系统版本了。

B 在fl库中一个获取系统中所有进程的函数

为了让我们的这个例子尽可能复杂,我不准备使用快照的方法去获取进程信息。而是使用Windows未公开的函数NtQuerySystemInformation。我在之前的《使用APIHOOK实现进程隐藏》中介绍过该方法。

#include <windows.h>#define MAXLOOPCOUNT 5
#define MAXPROCSSNUM 1024#define STATUS_SUCCESS 0x00000000
#define SystemProcessInformation 5
#define STATUS_SUCCESS 0x00000000
#define STATUS_INFO_LENGTH_MISMATCH ((ULONG)0xC0000004L)typedef DWORD (WINAPI * Fun_NtQuerySystemInformation)( DWORD, PVOID, DWORD, PDWORD );typedef struct _UNICODE_STRING {USHORT Length;USHORT MaximumLength;PWSTR  Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;typedef struct _SYSTEM_PROCESS_INFORMATION
{DWORD           dwNextEntryOffset;                  // 下段结构对象的偏移DWORD           dwNumberOfThreads;                  // 线程数LARGE_INTEGER   qSpareLi1;                          LARGE_INTEGER   qSpareLi2;LARGE_INTEGER   qSpareLi3;LARGE_INTEGER   qCreateTime;                        // 创建时间LARGE_INTEGER   qUserTime;                          // 用户态时间LARGE_INTEGER   qKernelTime;                        // 内核态时间UNICODE_STRING  ImageName;                          // 文件名(非路径)int             nBasePriority;                      // 基本优先级DWORD           dwProcessId;                        // 进程IDDWORD           dwInheritedFromUniqueProcessId;     // 父进程IDDWORD           dwHandleCount;                      // 句柄数DWORD           dwSessionId;ULONG           dwSpareUl3;SIZE_T          tPeakVirtualSize;SIZE_T          tVirtualSize;DWORD           dwPageFaultCount;DWORD           dwPeakWorkingSetSize;DWORD           dwWorkingSetSize;SIZE_T          tQuotaPeakPagedPoolUsage;SIZE_T          tQuotaPagedPoolUsage;SIZE_T          tQuotaPeakNonPagedPoolUsage;SIZE_T          tQuotaNonPagedPoolUsage;SIZE_T          tPagefileUsage;SIZE_T          tPeakPagefileUsage;SIZE_T          tPrivatePageCount;LARGE_INTEGER   qReadOperationCount;LARGE_INTEGER   qWriteOperationCount;LARGE_INTEGER   qOtherOperationCount;LARGE_INTEGER   qReadTransferCount;LARGE_INTEGER   qWriteTransferCount;LARGE_INTEGER   qOtherTransferCount;
}SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;BOOL GetNtQuerySystemInfoBuffer( IN DWORD SystemInformationClass, void** lpBuffer )
{BOOL bSuccess = FALSE;HMODULE hNtDll =  NULL;Fun_NtQuerySystemInformation NtQuerySystemInformation = NULL;ULONG cbBuffer = 0x0001;ULONG ulNeedBytes = cbBuffer;int nloopcount = 0;ULONG nstatus = 0;void* pBuffer = NULL;*lpBuffer = NULL;hNtDll = GetModuleHandle( L"ntdll.dll" );do {if( NULL == hNtDll ) {// 加载ntdll失败,返回FALSEbreak;}NtQuerySystemInformation = ( Fun_NtQuerySystemInformation ) GetProcAddress( hNtDll, "NtQuerySystemInformation" );if ( NULL == NtQuerySystemInformation ) {// 获取导出函数NtQuerySystemInformation失败,返回FALSEbreak;}// 预分配的空间大小,先分配一个小空间,理论上使用这个空间去获取信息是失败的cbBuffer = 0x0001;ulNeedBytes = cbBuffer;// 分配内存用于保存进程信息,只分配不释放,由外部释放*lpBuffer = malloc( cbBuffer );nloopcount = 0;do {// 为了防止无限循环,做个最大循环限制if ( nloopcount > MAXLOOPCOUNT ) {break;}nloopcount++;if( NULL == *lpBuffer ) {// 分配内存失败,返回FALSEbreak;}// 理论上,第一次执行这个函数会失败的,因为分配的空间太小nstatus = NtQuerySystemInformation( SystemInformationClass, *lpBuffer,cbBuffer,&ulNeedBytes );if ( STATUS_INFO_LENGTH_MISMATCH == nstatus ) {// 理论上,第一次执行NtQuerySystemInformation后会进入这里进行内存的再次扩容cbBuffer = ulNeedBytes;// 重新分配内存用于保存进程信息,只分配不释放,由外部释放pBuffer = realloc( *lpBuffer, cbBuffer );if (pBuffer != NULL)*lpBuffer = pBuffer;continue;}else if ( STATUS_SUCCESS == nstatus ) {// 成功bSuccess = TRUE;break;}else {// 非内存大小分配不够导致的错误bSuccess = FALSE;break;}} while(1);} while( 0 );if ( NULL != hNtDll ) {FreeLibrary( hNtDll );hNtDll = NULL;}if ( FALSE == bSuccess ) {// 如果获取信息失败,则释放分配的内存if ( NULL !=  *lpBuffer ) {free( *lpBuffer );*lpBuffer = NULL;}}return bSuccess;
}  

看到如上结构体,要是在lua中用ffi去声明,岂不是很崩溃!我们再看下填充数据的辅助函数

BOOL GetProcessFullInfo(lua_State *L)
{BOOL bSuccess = FALSE;PSYSTEM_PROCESS_INFORMATION pInfo = NULL;int nloopcount = 0;do {LPVOID pBuffer = NULL;if ( FALSE == GetNtQuerySystemInfoBuffer( SystemProcessInformation, &pBuffer) ) {// 获取失败,直接返回,不用释放pBuffer,因为GetZwQuerySystemInfoBuffer内部就释放了break;}if ( NULL == pBuffer ) {break;}pInfo = ( PSYSTEM_PROCESS_INFORMATION ) pBuffer;nloopcount = 0;lua_newtable( L );while( NULL != pInfo ) {// 为了防止无限循环,做个最大进程数限制if ( nloopcount > MAXPROCSSNUM ) {break;}nloopcount++;if( 0 == pInfo->dwNextEntryOffset ) {// 找到末尾最后一个了,就退出循环break;}else {lua_pushinteger( L, pInfo->dwProcessId);//lua_newtable( L );lua_pushinteger( L, pInfo->dwInheritedFromUniqueProcessId );lua_pushlstring( L, (char*)pInfo->ImageName.Buffer, pInfo->ImageName.Length );lua_settable( L, -3 );//lua_settable( L, -3 );// 利用偏移,找到下一个结构对象pInfo = ( PSYSTEM_PROCESS_INFORMATION)( ( (PUCHAR) pInfo ) + pInfo->dwNextEntryOffset );}}if ( NULL != pBuffer ) {free( pBuffer );pBuffer = NULL;}bSuccess = TRUE;} while( 0 );return bSuccess;
}

该函数生成一个如同

struct PINFO{
DWORD dwPPID; // 父进程ID
wstring wstrProcessName; // 本进程名字
};struct PINFOEX{
DWORD dwPID;  // 本进程ID
PINFO Info;
}list<PINFOEX> PINFOLIST;

的结果。

如果我们执行如此简短的Lua脚本

fl = require "fl"
allprocessinfo = fl.GetAllProcess()
for PID,item in pairs(allprocessinfo) dofor PPID,PNAME in pairs(item) doprint(PPID,PNAME)end
end

将把我们系统中进程信息打印出来。

介绍Luajit嵌入win32程序的文章讲完了。

最后,该工程源码都在以下链接:http://pan.baidu.com/s/1geQ10R5 密码:pknq

在windows程序中嵌入Lua脚本引擎--编写自己的Lua库相关推荐

  1. 在windows程序中嵌入Lua脚本引擎--建立一个简易的“云命令”执行的系统

    在<在windows程序中嵌入Lua脚本引擎--使用VS IDE编译Luajit脚本引擎>开始处,我提到某公司被指责使用"云命令"暗杀一些软件.本文将讲述如何去模拟一个 ...

  2. 在windows程序中嵌入Lua脚本引擎--使用VS IDE编译Luajit脚本引擎

    前些天听到一个需求:某业务方需要我们帮忙清理用户电脑上的一些废弃文件.同事完成这个逻辑的方案便是在我们程序中加入了一个很"独立"的业务逻辑:检索和删除某个程序产生的废弃文件.试想, ...

  3. Windows编译安装AzerothCore魔兽世界开源服务端Lua脚本引擎Eluna和防作弊anticheat模块教程

    Windows编译安装AzerothCore魔兽世界开源服务端Lua脚本引擎Eluna和防作弊anticheat模块教程 大家好,我是艾西今天和大家聊聊魔兽世界游戏内的脚步以及防作弊模块 Eluna是 ...

  4. 在WinForm程序中嵌入ASP.NET[转]

    在WinForm程序中嵌入ASP.NET 现在的流行趋势是桌面程序Web化,Web程序桌面化,呵呵.最终目标就是你中有我,我中有你.例如MSN Explorer就是一个很好的展示,让用户在使用的时候分 ...

  5. Cocos2d-x之LUA脚本引擎深入分析

    FROM:http://www.2cto.com/kf/201303/197171.html 原文内容如下: 首先,我们要知道LUA是个什么东西,至于官方怎么说可以百度去查,但我想告诉你的是LUA就是 ...

  6. perlembed - 在 C 程序中嵌入 perl

    NAME     perlembed - 在 C 程序中嵌入 perl DESCRIPTION   导言     你是想要: 在 Perl 中使用 C?          阅读 perlxstut.p ...

  7. 在WinForm应用程序中嵌入WPF控件(转)

      我们知道,在WPF界面上添加WinForm的控件需要使用WindowsFormHost类.而在WinForm界面上添加WPF控件该如何做呢?有没有类似的类呢?明显是有的,ElementHost就是 ...

  8. php 嵌入手机百度地图,C# 程序中嵌入百度地图

    本例是对WinForm中使用百度地图的简要介绍.百度地图目前支持Android开发,IOS开发,Web开发,服务接口,具体可以参照'百度地图开放平台'. [动态加载百度地图]涉及到的知识点:WebBr ...

  9. 如何在程序中嵌入FOP

    如何在程序中嵌入FOP 内容: FOP使用方式 介绍 参考资料 关于作者 FOP 简介 马 路 (stevema@263.net) 2001 年 11 月 如何在程序中嵌入FOP?FOP是由James ...

最新文章

  1. java request get json数据_Java中,获取request中json数据
  2. 安装server 2012 时提示输入的密码不满足网络或组管理员设置的密码复杂度
  3. Java注释 link_开源代码中注释中的那些a link p @ 是给什么编辑器用的????
  4. Eclipse开发环境设置
  5. linux逻辑文件块,linux逻辑卷组创建以及修改
  6. pandas—总结(2) 数据读写 (更新中)
  7. php 特殊字符¥,php正则怎么替换符号
  8. Ajax Loader 图标
  9. 直线插补计算过程_【计鹏视角】风速数据插补对发电量的影响
  10. NetTiers学习笔记12---deepload的递归
  11. Navicat for MySQL 64位破解版
  12. CentOS 迁移SVN以及可视化管理工具iF.SVNAdmin
  13. LTE 调制与解调——QPSK,16QAM,64QAM误码率比较
  14. 《中国各省名由来》 2010年11月03日
  15. 捷讯fw300r虚拟服务器口号,迅捷FW300R开启UPnP功能
  16. CRM系统提高企业核心竞争力
  17. openCV——轮廓检测
  18. 08 干系人管理ITO
  19. iPhone启动页尺寸
  20. coco参考文档网址

热门文章

  1. opencv数字图像处理(图像模糊)
  2. 使用Python、OpenCV进行图像接缝雕刻
  3. 力扣(LeetCode)刷题,简单题(第8期)
  4. 【Pandas库】(3) DataFrame的创建方法及基本操作
  5. 二、如何保存MNIST数据集中train和test的图片?
  6. java 读取流的字符编码格式_如何使用Java代码获取文件、文件流或字符串的编码方式...
  7. java 二分搜索获得大于目标数的第一位_程序员常用查找算法(顺序、二分、插值、分块、斐波那契)...
  8. 常见浏览器User-Agent大全
  9. C#和Unity编码和游戏开发学习教程
  10. C语言网络编程:TCP客户端实现