找回密码
 点一下
查看: 10700|回复: 19

JAPI基本原理及应用(续)

[复制链接]
发表于 2009-2-10 17:10:02 | 显示全部楼层 |阅读模式
  1. 阅读本文前,请先阅读
  2. JAPI基本原理及应用(未完待续.......)
  3. [url]http://www.islga.org/bbs/read.php?tid=12371[/url]
复制代码

rahxephon为japi揭开了冰山一角,苦等一年却没有下文,只好自己摸索,略有心得,不敢独享。

一、搜索BindNative函数

上文说到只要将某一处的CALL Game.6F69DC30改为我们自己的函数就能给jass添加新函数,但是还有一个问题,怎么知道这个CALL Game.6F69DC30在哪呢?不同版本的game.dll的CALL Game.6F69DC30的位置不一样,绑定Native函数的地址也不总是6F69DC30,用固定地址只能在特定的war3版本中使用。

用上次的方法在OD里随便搜一个jass函数,可以看到下面的数据:
  1. 6F3CF20F    B9 F0DC3A6F     mov     ecx, 6F3ADCF0
  2. 6F3CF214    E8 07680700     call    6F445A20
  3. 6F3CF219    68 D826926F     push    6F9226D8        ; ASCII "()V"
  4. 6F3CF21E    BA E443936F     mov     edx, 6F9343E4   ; ASCII "DoNotSavplay"
  5. 6F3CF223    B9 10DD3A6F     mov     ecx, 6F3ADD10
  6. 6F3CF228    E8 F3670700     call    6F445A20
  7. 6F3CF22D    68 E489936F     push    6F9389E4        ; ASCII "(II)I"
  8. 6F3CF232    BA D443936F     mov     edx, 6F9343D4   ; ASCII "GetRandomInt"
  9. 6F3CF237    B9 20DD3A6F     mov     ecx, 6F3ADD20
  10. 6F3CF23C    E8 DF670700     call    6F445A20
  11. 6F3CF241    68 D892936F     push    6F9392D8        ; ASCII "(RR)R"
  12. 6F3CF246    BA C443936F     mov     edx, 6F9343C4   ; ASCII "GetRandomReal"
  13. 6F3CF24B    B9 60DD3A6F     mov     ecx, 6F3ADD60
  14. 6F3CF250    E8 CB670700     call    6F445A20
复制代码

仔细想下OD是怎么知道绑定Native函数的地址在这里的?对,是通过CJ函数的函数名,我们也可以偷偷学下OD的办法。
mov     edx, 6F9343C4   ; ASCII "GetRandomReal"
是把"GetRandomReal"字符串的地址6F9343C4压栈,来到6F9343C4地址可以看到
pic1.jpg
这里其实就是保存"GetRandomReal"的asccii码,好了,现在已经可以动手写个搜索函数了。总结下步骤
1、搜索game.dll里的"GetRandomReal"字符串,取得其首地址(当然也可以是其他函数)
2、搜索这个地址出现的位置
3、第二步的值加0x09就是call BindNativeFunc的地址了。

当然搜索"GetRandomReal"只需在.rdata段(122)和.data段(120)里搜,搜索地址只需在.text段里搜,熟悉PE文件结构的同学都应该知道。

好了这次真的可以写属于我们自己的japi.dll了。

二、数据转换

当你兴致勃勃地动手写第一个属于自己的jass函数时,你会郁闷地发现,jass虚拟机传进来的的参数,无论handle,string,integer还是real,全部一律是int。所以有必要把jass内部的数据转换函数找到,这样才能真正读到jass的变量里的内容。那么就从string开始吧。先找个用string作为输入参数的jass函数来看下,比如S2I,这次改用IDA,用老方法来到S2I的函数这里:
  1. .text:6F3AD4F0 jassS2I         proc near               ; DATA XREF: sub_6F3CBA60+14Fo
  2. .text:6F3AD4F0
  3. .text:6F3AD4F0 arg_0           = dword ptr  4
  4. .text:6F3AD4F0
  5. .text:6F3AD4F0                 mov     ecx, [esp+arg_0]
  6. .text:6F3AD4F4                 call    sub_6F4B4990
  7. .text:6F3AD4F4
  8. .text:6F3AD4F9                 test    eax, eax
  9. .text:6F3AD4FB                 jz      short loc_6F3AD50C
  10. .text:6F3AD4FB
  11. .text:6F3AD4FD                 cmp     byte ptr [eax], 0
  12. .text:6F3AD500                 jz      short loc_6F3AD50C
  13. .text:6F3AD500
  14. .text:6F3AD502                 mov     [esp+arg_0], eax
  15. .text:6F3AD506                 jmp     ds:atoi
  16. .text:6F3AD506
  17. .text:6F3AD50C ; ---------------------------------------------------------------------------
  18. .text:6F3AD50C
  19. .text:6F3AD50C loc_6F3AD50C:                           ; CODE XREF: jassS2I+Bj
  20. .text:6F3AD50C                                         ; jassS2I+10j
  21. .text:6F3AD50C                 xor     eax, eax
  22. .text:6F3AD50E                 retn
复制代码

这个函数很短,过程也很容易看得懂,先调用sub_6F4B4990取得一个地址,然后用atoi函数转换成int,显然sub_6F4B4990就是我们想要的字符串转换函数。依然可以用上面说过的搜索法,得到这个地址,以便适用于所有版本的war3。

很简单吧,其他的数据类型也是用类似的方法,不再细述。

三、操纵全局变量

这个稍微复杂些。静态分析已经看不出什么端倪了,我们来调试下war3,找到war3读写全局变量的方法。

先准备一个测试地图,这里只贴关键部分。
[codes=jass]
function act takes nothing returns nothing
    set udg_actboy168 = GetRandomInt(1000,2000)
endfunction

function test takes nothing returns nothing
    local timer t = CreateTimer()
    call TimerStart(t, 1.0, TRUE, function act)
endfunction
[/codes]

然后在GetRandomInt函数的出口处下一个断点(自然是用OD了),然后单步跟踪吧,仔细观察寄存器值的变化,这里需要一些耐心,在6F44F4B7附近(我的是122),"udg_actboy168"这个字符串终于出现了,想必读取全局变量地址的函书就在附近。单步跟踪附近的几个call,获得全局变量地址的函数就在这里
  1. .text:6F44F4C0                 mov     ecx, [esi+2858h]
  2. .text:6F44F4C6                 push    ebp
  3. .text:6F44F4C7                 call    sub_6F43D4F0
复制代码
在数据窗口里查看从这个函数返回的值的位置,地址+20处,正是上一次全局变量的值(因为这里还没改),觉得不放心也可以多做几次来验证。

这个函数有两个输入参数,一个是ebp,就是变量名,另一个是[esi+2858h],想必就是一个记录全局变量的表的地址。esi想必就是jass虚拟机类的地址。

沿着此处一路向上跟踪esi的值是怎么来的,可以在6F43BF73处发现,这里call    sub_6F43BC10后就得到了这个值,一直传到后面去。sub_6F43BC10实际就是调用了TlsGetValue来得到,不管怎么样,我们可以通过直接调用sub_6F43BC10来得到这个值。不过sub_6F43BC10还有个输入参数,用OD在这里下断发现这个参数永远是2。

好了,获取全局变量地址的方法我们已经找到了
1、用sub_6F43BC10得到jass虚拟机类
2、用sub_6F43D4F0得到全局变量的地址
3、地址+20就是全局变量的值

等等,还有一个问题没有解决,那就是sub_6F43BC10函数和sub_6F43D4F0函数的地址,为了通用性,还必须通过搜索game.dll的方法来得到。

对于sub_6F43BC10,向上查找可以找到一个"config"字符串,利用它来定位吧;对于sub_6F43D4F0,我的方法是,自己写一个,照抄代码即可。

四、调用CJ函数

这个...还记得怎么搜索CJ函数地址吧。

五、后记
至此,我们编写jass内部函数已经和在jass里面写函数没什么区别了。希望此文能给你一些启发。
发表于 2009-2-10 18:02:04 | 显示全部楼层
支持一下   JAPI啊~~~叫阿皮啊~~
回复

使用道具 举报

发表于 2009-2-10 18:07:43 | 显示全部楼层
有心人看到的话~~应该是精了~~
回复

使用道具 举报

发表于 2009-2-10 20:24:10 | 显示全部楼层
是的
回复

使用道具 举报

发表于 2009-2-10 22:46:28 | 显示全部楼层
恩,鼓掌,有人帮偶续写太好了。。。

话说偶写过那文章后不久就进入某国企工作鸟,天天加班实在是没心思干这些了。。。- -
回复

使用道具 举报

发表于 2009-2-11 20:58:17 | 显示全部楼层
收藏起``希望ls lz继续多发表些研究结果```~
回复

使用道具 举报

发表于 2009-2-11 22:12:54 | 显示全部楼层
actboy 你~~~~~~~~~~~~~~~~~~太强大了~~~~~~~~~~~~~~~~


你让 我们这些菜鸟 太自卑了~
回复

使用道具 举报

发表于 2009-2-12 07:03:21 | 显示全部楼层
gg平台。。永远的痛
回复

使用道具 举报

发表于 2009-2-12 10:30:20 | 显示全部楼层
ls思维跳跃好大`~~
竞舞台 似乎我很久没去了
回复

使用道具 举报

发表于 2009-2-13 09:06:12 | 显示全部楼层
恩 其实只要有足够的空间 (比如把不需要的函数统统干掉)

在定义函数那里可以继续定义新的

push    参数类型地址(搜索一下)
mov     edx, 函数名地址
mov     ecx, 函数实际地址
call    6F445A20

这样不用japi或任何形式loader也可以自定义函数哟
好处是兼容性很好很强大,其权限基本等于暴雪函数,很难被针对禁止,不像loader问题多多
回复

使用道具 举报

发表于 2009-2-18 20:10:40 | 显示全部楼层
只能重写CJ函数,不能去掉

因为地图加载的时候,虚拟机会初始化所有的CJ函数,如果被你去掉了一些,自己的图没问题,但是一旦加载别人的图,会导致魔兽认为脚本有错(函数找不到)而拒绝加载。

检测这种行为也不复杂,对关键代码计算校验和就可以查出来了

japi自己使用的搜索策略是,搜索内存特征码(内存数据和特征掩码做按位与(&)运算得到特征码, 然后和预先储存的特征码比较,相同即认为这里是函数)
这种策略也是可行的
回复

使用道具 举报

发表于 2009-2-18 22:21:20 | 显示全部楼层
呵呵 当然要配合修改版的CJ来用啦。。
回复

使用道具 举报

发表于 2009-2-19 09:49:04 | 显示全部楼层
恩,是的,不过不能指望其他人的图也使用修改版的CJ
回复

使用道具 举报

 楼主| 发表于 2009-2-19 22:53:42 | 显示全部楼层
别人的game.dll又没改自然不用改CJ文件.......
回复

使用道具 举报

发表于 2009-5-19 18:24:00 | 显示全部楼层
你写的文章我读了很多天,自己学习了 OD的使用,动态修改目标进程的代码,结果目前在网上仅存的三篇文章,一篇是白银翻译的,一篇是rahxephon 的JAPI基本原理及应用(未完待续.......),最后一篇是你写的这篇,我研究好久,文章我全读懂了,但是具体 实现一个自己义的JASS函数还是困难,诚心希望得到你的帮助,我的QQ675491402
回复

使用道具 举报

 楼主| 发表于 2009-5-21 14:33:06 | 显示全部楼层
回复

使用道具 举报

发表于 2010-3-28 12:19:00 | 显示全部楼层
不同版本的game.dll的CALL Game.6F69DC30的位置不一样,绑定Native函数的地址也不总是6F69DC30,用固定地址只能在特定的war3版本中使用。
比如我要1.24b支持 是怎么做法呢?
回复

使用道具 举报

发表于 2015-6-28 08:34:14 | 显示全部楼层

   你的意思就是 运行了dll文件以后看 dll文件里面预载的 对应的函数在哪个内存?  有意义吗?  

   添加了新的函数 运行war3以后,如果预载所有的函数,新函数的地址就不一样。如果不预载所有函数,你知道地址在哪里又有什么用?
回复

使用道具 举报

发表于 2017-6-15 23:02:00 | 显示全部楼层
会汇编的人愈来愈少了
回复

使用道具 举报

发表于 2017-6-15 23:02:14 | 显示全部楼层
会汇编的人愈来愈少了
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-12-22 10:08 , Processed in 0.137900 second(s), 22 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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