设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 1900|回复: 1
打印 上一主题 下一主题

[RMXP发布] 开源,混乱的产物,脚本编辑器改造。

[复制链接]

Lv1.梦旅人

梦石
0
星屑
81
在线时间
54 小时
注册时间
2008-12-24
帖子
345
跳转到指定楼层
1
发表于 2016-7-11 14:23:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
我已经很久不玩 RMXP了。
某个瞬间我看到了一个 iD[猫哥哥] 发的一篇文章 [RMXP发布] RMXP脚本编辑器不完全调教= =||[更新到v1.1]
虽然去 玩C++ 很久了,但也没有写出一个成品。。。唉。
废话不多说了。
首先编译 scintilla 开源库 在 DLLmain 入口函数 加入 LoadLibrary() -》 代替注入。
[pre lang="c++" line="0"]
// 这个是拦截 脚本编辑器 创建 裸函数。。。 this call
__declspec(naked) int sub_49B840()
{
    _asm
    {
        push ebp;
        mov ebp, esp;
        push dword ptr [ebp+16];
        push dword ptr [ebp+12];
        push dword ptr [ebp+8];
        push ecx;
        call SCICreateEx;
        mov esp, ebp;
        pop ebp;
        ret 12;
    }
}

CSimHook g_pHookSCICreate(0x09B840, (int)(sub_49B840));

BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
{
        switch (dwReason)
        {
        case DLL_PROCESS_ATTACH:
        {
            g_pHookSCICreate.Rehook();
            break;
        }
        case DLL_PROCESS_DETACH:
        {
            break;
        }
        }
        return TRUE;
}

HWND g_hSCIWnd = NULL;
HWND g_hSCIWndParent = NULL;
SciFnDirect g_fnDirect = NULL;
sptr_t g_ptrDirect = NULL;
WNDPROC g_pfnWndProc = NULL;
WNDPROC g_pfnParentWndProc = NULL;

__inline sptr_t SendEditor(unsigned int iMessage, uptr_t wParam = 0, sptr_t lParam = 0)
{
    return g_fnDirect(g_ptrDirect, iMessage, wParam, lParam);
}

#define MARGIN_FOLD_INDEX 2
#include "xpm.h"

int WINAPI SCICreateEx(int pThis, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    // 初始化 其实这个放在 子类化后的销毁消息中最好
    g_hSCIWnd = NULL;
    g_hSCIWndParent = NULL;
    g_fnDirect = NULL;
    g_ptrDirect = NULL;
    g_pfnWndProc = NULL;
    g_pfnParentWndProc = NULL;
    // 调用源流程
    g_pHookSCICreate.Unhook();
    int callptr = g_pHookSCICreate.GetPtr();
    _asm
    {
        pushad;   // 其实非 this call fast call 不一定要保护寄存器
        push dword ptr [lParam];
        push dword ptr [wParam];
        push dword ptr [uMsg];
        mov ecx, dword ptr [pThis];
        call dword ptr [callptr];
        mov dword ptr [callptr], eax;
        popad;
    }
    g_pHookSCICreate.Rehook();
    // 进行修正
    int * pSCIWnd = (int*)(pThis + 0x20);
    g_hSCIWnd = (HWND)(*pSCIWnd);
    if (g_hSCIWnd != NULL)
    {
        // 取父窗口
        g_hSCIWndParent = ::GetParent(g_hSCIWnd);
        if (g_hSCIWndParent != NULL)
        {
            g_fnDirect = (SciFnDirect)SendMessage(g_hSCIWnd, SCI_GETDIRECTFUNCTION, 0, 0);
            g_ptrDirect = (sptr_t)SendMessage(g_hSCIWnd, SCI_GETDIRECTPOINTER, 0, 0);
            if ((g_ptrDirect != NULL) && (g_fnDirect != NULL))
            {
                // 子类化窗口
                g_pfnWndProc = (WNDPROC)::SetWindowLong(g_hSCIWnd, GWL_WNDPROC, (long)SCIWndProc);
                g_pfnParentWndProc = (WNDPROC)::SetWindowLong(g_hSCIWndParent, GWL_WNDPROC, (long)SCIParentWndProc);
                SendEditor(SCI_SETCODEPAGE, SC_CP_UTF8);  // utf - 8
                SendEditor(SCI_SETLEXER, SCLEX_RUBY);                               // 设置 RUBY 解析器
                SendEditor(SCI_STYLESETFONT, STYLE_DEFAULT, (sptr_t)"Courier New"); // 设置默认字体
                SendEditor(SCI_STYLESETSIZE, STYLE_DEFAULT, 10);                    // 设置默认字号
                SendEditor(SCI_SETPROPERTY, (sptr_t)"styling.within.preprocessor", (sptr_t)"1");  // 使预处理符后面的关键词能够使用高亮着色风格
                // 设置关键字
                // 设置风格
                SendEditor(SCI_STYLESETFORE, SCE_RB_DEFAULT, RGB(255, 255, 255));
                SendEditor(SCI_STYLESETFORE, SCE_RB_ERROR, RGB(255, 0, 0));
                SendEditor(SCI_STYLESETFORE, SCE_RB_COMMENTLINE, RGB(0, 128, 0));   // 行注释
                // SendEditor(SCI_STYLESETFORE, SCE_RB_POD 3
                SendEditor(SCI_STYLESETFORE, SCE_RB_NUMBER, RGB(128, 0, 0));        // 数字
                //SendEditor(SCI_STYLESETFORE, SCE_RB_WORD 5
                SendEditor(SCI_STYLESETFORE, SCE_RB_STRING, RGB(128, 0, 128));      // 字符串
                SendEditor(SCI_STYLESETFORE, SCE_RB_CHARACTER, RGB(128, 10, 128));  // 字符
                SendEditor(SCI_STYLESETFORE, SCE_RB_CLASSNAME, RGB(0, 0, 255));     // 类名
                SendEditor(SCI_STYLESETFORE, SCE_RB_DEFNAME, RGB(4, 153, 190));     // 定义名
                SendEditor(SCI_STYLESETFORE, SCE_RB_OPERATOR, RGB(0, 0, 128));      // 操作符
                SendEditor(SCI_STYLESETFORE, SCE_RB_IDENTIFIER, RGB(0, 0, 160));    // 标识符
                SendEditor(SCI_STYLESETFORE, SCE_RB_REGEX, RGB(0, 20, 160));        // 正则表达式
                SendEditor(SCI_STYLESETFORE, SCE_RB_GLOBAL, RGB(160, 0, 160));      // 全局变量
                SendEditor(SCI_STYLESETFORE, SCE_RB_SYMBOL, RGB(223, 52, 52));      // 符号

                SendEditor(SCI_STYLESETFORE, SCE_RB_MODULE_NAME, RGB(223, 52, 252));      // 模块名
                SendEditor(SCI_STYLESETFORE, SCE_RB_INSTANCE_VAR, RGB(223, 152, 52));     // 实例变量
                SendEditor(SCI_STYLESETFORE, SCE_RB_CLASS_VAR, RGB(23, 152, 52));        // 类变量

                 // 设置折叠
                SendEditor(SCI_SETTABWIDTH, 4);
                SendEditor(SCI_SETPROPERTY, (sptr_t)"fold", (sptr_t)"1");
                SendEditor(SCI_SETMARGINCURSORN, MARGIN_FOLD_INDEX, SC_CURSORARROW);
                // 折叠标签样式

                SendEditor(SCI_SETMARGINTYPEN, MARGIN_FOLD_INDEX, SC_MARGIN_SYMBOL);// 页边类型
                SendEditor(SCI_SETMARGINMASKN, MARGIN_FOLD_INDEX, SC_MASK_FOLDERS); // 页边掩码
                SendEditor(SCI_SETMARGINWIDTHN, MARGIN_FOLD_INDEX, 11);             // 页边宽度
                SendEditor(SCI_SETMARGINSENSITIVEN, MARGIN_FOLD_INDEX, TRUE);       // 响应鼠标消息
                // 折叠标志 XPM
                SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_PIXMAP);
                SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_PIXMAP);
                SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEREND, SC_MARK_PIXMAP);
                SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPENMID, SC_MARK_PIXMAP);
                SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNERCURVE);
                SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE);
                SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNERCURVE);
                //
                SendEditor(SCI_MARKERDEFINEPIXMAP, SC_MARKNUM_FOLDER, (sptr_t)plus_xpm);
                SendEditor(SCI_MARKERDEFINEPIXMAP, SC_MARKNUM_FOLDEROPEN, (sptr_t)minus_xpm);
                SendEditor(SCI_MARKERDEFINEPIXMAP, SC_MARKNUM_FOLDEREND, (sptr_t)plus_xpm);
            }
        }
    }
    return callptr;
}


// Sci 窗口过程
LRESULT WINAPI SCIWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case SCI_STYLESETFONT:                 
        {
            break;
        }
    }
    return ::CallWindowProc(g_pfnWndProc, hWnd, uMsg, wParam, lParam);
}

// Sci 父窗口过程
LRESULT WINAPI SCIParentWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if ((uMsg == WM_NOTIFY) && (lParam != NULL))
    {
        NMHDR * lnmhdr = (NMHDR*)lParam;
        if (lnmhdr->hwndFrom == g_hSCIWnd)
        {
            SCNotification * lSCNmhdr = (SCNotification*)lParam;
            switch (lnmhdr->code)
            {
            case SCN_STYLENEEDED:
            case SCN_CHARADDED:
            case SCN_SAVEPOINTREACHED:
            case SCN_SAVEPOINTLEFT:
            case SCN_MODIFYATTEMPTRO:
            case SCN_DOUBLECLICK:
            case SCN_UPDATEUI:
            case SCN_MODIFIED:
            case SCN_MACRORECORD:
                break;
            case SCN_MARGINCLICK:  /// 旁注栏被单击
                {
                    SendEditor(SCI_TOGGLEFOLD, SendEditor(SCI_LINEFROMPOSITION, lSCNmhdr->position));
                    break;
                }
            }
        }
    }
    return ::CallWindowProc(g_pfnParentWndProc, hWnd, uMsg, wParam, lParam);
}[/pre]
当然这个很简单。
我脱壳 RMXP 后 用 OD 逆向 IDA 辅助 逆向出了以下代码
RGSSGetInt("$data_scripts.size")  // 取脚本数量
RGSSGetStringACP (“$data_scripts ”)    // 取指定脚本名称
RGSSGetStringUTF8 (“Zlib::Inflate.inflate($data_scripts )”) // 解码脚本
可以说 在内部, 脚本是用 RUBY 进行保存的。

说说自动完成吧,问题就在这里,如果这个成功了。我也不会放弃。
在我编写脚本分析器 困难重重,首先 我学到编程 脚本 太多 乱。个人能力不行,
参考了很多开源的 RUBY IDE 中,
很多人都说 RUBY 很多变量 类型 是要在运行后才能确定 所以词法 语法分析 没有一定功力是无法完成的,我这里也只写了一点点
[pre lang="c++" line="0"]
// 跳过注释
int WINAPI seek_remark(char * str, int len)
{
    do
    {
        switch (*str++)
        {
        case '#':
            {
                char * s = str;
                do
                {
                    char chr = *s++;
                    switch (chr)
                    {
                    case '\r':
                        return (*s == '\n')?(int(s) - int(str) + 2):(int(s) - int(str) + 1);
                    case '\n':
                    case '\0':
                        return int(s) - int(str) + 1;
                    default:
                        {
                            if (isHighBitChar(chr))
                                s++;
                            break;
                        }
                    }
                } while (1);
            }
        case '=':
            {
                // =begin=end
                if (_PINT(str) == REMARK_BEGIN_DWORD) // 0 1 2 3
                {
                    str += sizeof(DWORD);
                    if (*str++ == 'n')
                    {
                        int i = _strstr(str, "=end", len - 6, 4);
                        return (i != -1)?(10+i):len;
                    }
                }
                return 0;
            }
        }
    } while (1);
    return 0;
}

// 解析到下个字符串包围壳
int parsing_string_symbol(char * str, char symbol)
{
    char * s = str;
    do
    {
        char c = *s++;
        if (c == symbol)
            return (int)(s - str);
        else if (c == '\\')  // 忽略下个符号
            s += isHighBitChar(*s)?2:1;
        else if (isHighBitChar(c))
            s++;
    } while (1);
    return 0;
}
// 解析数值
int parsing_num(char * str)
{
    char * s = str;
    do
    {
        switch (*s++)
        {
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
        case '.':
            {
                break;
            }
        default:
            return (int(s - str));
        }           
    } while (1);
    return 0;
}
// 寻文本 sunday 算法
int _strstr(char * src, char * des, int len_s, int len_d)
{
    // if (len_d == 0) len_d = _strlen(des);
    int i = 0;
    int j = 0;
    int pe = len_d - 1;
    int tb = i;
    int te = len_s - 1;
    while ((i < len_s) && (j < len_d))
    {
        if (src == des[j])
        {
            i++;
            j++;
        }
        else
        {
            int k = len_d - 1;
            while (k >= 0 && src[pe + 1] != des[k])
            {
                k--;
            }
            int gap = len_d - k;
            i += gap;
            pe = i + len_d - 1;
            tb = i;
            j = 0;
        }
    }
    if (i <= len_s)
    {
        return tb;
    }
    return -1;
}[/pre]
我也想过用 ctags 生成 tag list 可惜在 ctags 在 ruby 分析中 类 实例变量  与 全局变量 都无法分析出。⊙﹏⊙!算了 说多了,都是泪。
丧尸语录-终の千年
类型:恐怖
      爱情
      悬疑
      休闲
の名:千年の制裁の
系统--- 50%
画面---  0%
美工---  0%
地图---  0%
数据库-  0%
剧情---  50%

Lv4.逐梦者

梦石
0
星屑
9275
在线时间
2504 小时
注册时间
2011-5-20
帖子
15389

开拓者

2
发表于 2016-7-12 11:01:27 | 只看该作者
这···脚本没框到啊···
[img]http://service.t.sina.com.cn/widget/qmd/5339802982/c02e16bd/7.png
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-5-1 07:35

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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