找回密码
 点一下
查看: 1718|回复: 5

自定义Galaxy API

[复制链接]
发表于 2011-6-5 22:10:42 | 显示全部楼层 |阅读模式
警告:此篇文章涉及的内容可能违反《星际争霸II》及《星际争霸II地图编辑器》最终用户协议,仅供技术研究,非法使用责任自负。

曾经jass有过自定义native的研究,叫做jAPI。星际2作为暴雪游戏,其结构和原理都与魔兽非常相似。当然,具体细节还是有不同的。
根据aeris的这篇帖子(http://bbs.islga.org/read-htm-tid-39991.html),以及后续研究,星际2的native注册是放置了一个结构体(位于.rdata),而后程序扫描注册,不同于jass的函数名和地址都写死在.code的做法。

用反汇编打开星际2程序(IDA或者带隐藏插件的OD,推荐allydbg),代码段搜索特征码
8D A4 24 00 00 00 00 57 8B C6 E8 ,代码位置-4 byte 即为native注册信息结构体的指针(实际为一句指令的一部分,little endian)

以注册信息结构体指针地址为准,
+0x1B byte 即为注册时判断native结束地址.
其余参考aeris的帖子就很容易懂了。

如果想要自定义一个新的native,有两种办法:
1. 修改这个结构体的内容
2. 修改代码,让它使用位于另一个地址的结构体

实际上1并不可行,因为结构体的大小已经被限定了。
使用方法2可以把整个native注册结构体复制出来,并且在尾端添加自己的native,而后修改代码令其读取修改后的结构体。
不过仅仅修改注册还是不够的,因为在游戏内执行脚本时,还有一道关卡。
每个Galaxy native在编译成字节码时都会得到一个序号,也就是从1到总native数量的序号。
同时,Galaxy脚本中的函数调用也会被翻译为调用某序号的函数,
因此执行的时候会额外判断该序号函数是否存在,如果超过已知总数——注意这个总数是写死在.code中的——则不予以执行。

所以,对代码进行修改也是必须的:
在之前提到的注册信息结构体指针地址的 - 0xFE 和 -0xEF分别是galaxy运行时所判断结构体地址(用以转换脚本调用到函数调用),和函数总数量。

下面是一段不保证能编译的简单代码,注册了GetLocalPlayer函数,返回本地玩家(呵呵。。。。。。你懂的)
  1. /*
  2. const int Offset_NativeBeginHook    = ?
  3. // 8D A4 24 00 00 00 00 57 8B C6 E8    offset -0x4
  4. const int Offset_NativeEndHook      = ?
  5. // BeginHook + 0x1B
  6. const int Offset_NativeTotalCount   = ?
  7. // BeginHook - 0xFE
  8. const int Offset_NativeExecHook     = ?
  9. // BeginHook - 0xEF
  10. const int Offset_LocalPlayer      = ?
  11. // 55 8B EC 83 7D 08 00 74 11 83 3D ?? ?? ?? ?? 00 75 08 38 0D
  12. // Offset + 0x14
  13. */
  14. /* you need to include necessary libs here */
  15. DWORD *lpCurrentNativeInfo;
  16. int customNativeCount;
  17. DWORD *nativeBeginHook = (DWORD *)Offset_NativeBeginHook;
  18. DWORD *nativeEndHook = (DWORD *)Offset_NativeEndHook;
  19. int *nativeTotalCount = (int *)Offset_NativeTotalCount;
  20. DWORD *nativeExecHook = (DWORD *)Offset_NativeExecHook;
  21. DWORD oldNativeBeginHook;
  22. DWORD oldNativeEndHook;
  23. DWORD oldNativeExecHook;
  24. DWORD oldNativeTotalCount;
  25. void *lpSC2NativeInfo;
  26. void *lpnewNativeInfo;
  27. int nativeByteCount;
  28. void BindAllNatives ();
  29. BOOL DwPatch(DWORD *lpDwPatch, DWORD *lpOldVal, DWORD DwVal) {
  30.     DWORD dwOldProtect;
  31.     if(VirtualProtect(lpDwPatch, 4, PAGE_READWRITE, &dwOldProtect)){
  32.     if (lpOldVal){
  33.       *lpOldVal  = *lpDwPatch;
  34.     }
  35.         *lpDwPatch = DwVal;
  36.         return VirtualProtect(lpDwPatch, 4, dwOldProtect, &dwOldProtect);
  37.     }
  38.     return false;
  39. }
  40. void BindNative ( void *nativefunc, char *nativename, char returntype, char *paraminfo){
  41.   *((void **)lpCurrentNativeInfo + 0x0) = nativefunc;
  42.   *((char **)lpCurrentNativeInfo + 0x1) = nativename;
  43.   *((byte *)lpCurrentNativeInfo + 0x8) = strlen(paraminfo);
  44.   *((char *)lpCurrentNativeInfo+0x9) = returntype;
  45.   strcpy(((char *)lpCurrentNativeInfo + 0xA), paraminfo);
  46.   lpCurrentNativeInfo += ( 0x18 / 4 );
  47.   customNativeCount ++;
  48. }
  49. void DoPatch(){
  50.   DwPatch(nativeBeginHook,      &oldNativeBeginHook,  (DWORD)lpnewNativeInfo);
  51.   DwPatch(nativeEndHook,        &oldNativeEndHook,    (DWORD)lpCurrentNativeInfo);
  52. }
  53. /* called by main function */
  54. void InitNatives () {
  55.   lpSC2NativeInfo = (void *)*nativeBeginHook;//start loc
  56.   lpnewNativeInfo = malloc(0x12000); //create enough room for ~3072 nativeinfos
  57.   nativeByteCount = ( (int)*nativeEndHook - (int)*nativeBeginHook );
  58.   customNativeCount = 0;
  59.   if (lpnewNativeInfo) {
  60.     ZeroMemory( lpnewNativeInfo, 0x12000);
  61.     memcpy( lpnewNativeInfo,  lpSC2NativeInfo, nativeByteCount);//copy all natives
  62.     lpCurrentNativeInfo = (DWORD *)lpnewNativeInfo + nativeByteCount / 4;
  63.     BindAllNatives();
  64.     if (lpCurrentNativeInfo) {
  65.       *(DWORD *)lpCurrentNativeInfo = 0xFFFFFFFF;
  66.       DwPatch(nativeExecHook,       &oldNativeExecHook,   (DWORD)lpnewNativeInfo);
  67.       DwPatch((DWORD *)nativeTotalCount,  &oldNativeTotalCount, (DWORD)(customNativeCount + (nativeByteCount / 0x18)));
  68.       DoPatch();
  69.     }
  70.   }
  71. int GetLocalPlayer(void) {
  72.   return *(byte *) (Offset_LocalPlayer);
  73. }
  74. void BindAllNatives () {
  75.   //custom natives
  76.   BindNative(GetLocalPlayer,"GetLocalPlayer",'4',"-");
  77. }
复制代码

随后,你需要通过在地图中插入自定义natives.galaxy或者干脆在地图galaxy中声明该native:
  1. native int GetLocalPlayer ();
复制代码

这样自定义native就与暴雪提供的native一样可以使用了。
如果想要让编辑器一同支持自定义native,则还需要对编辑器exe做同样的事情,在此就留给大家自己寻找了。

评分

参与人数 1威望 +4 收起 理由
oneonestar + 4 违反用户协议

查看全部评分

发表于 2011-6-5 22:39:55 | 显示全部楼层
好Fine的东西~~
回复

使用道具 举报

发表于 2011-6-5 22:51:18 | 显示全部楼层
都牵涉的到代码了
回复

使用道具 举报

发表于 2011-6-5 23:30:48 | 显示全部楼层
终于来了么

但是只有战网能联机啊,没法普及起来
回复

使用道具 举报

发表于 2011-6-7 07:33:41 | 显示全部楼层
还有社么用法啊?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-4-28 21:59 , Processed in 0.126823 second(s), 22 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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