希望bm吧 关注:596贴子:1,050
  • 15回复贴,共1

CE汇编:定义全局变量(数据),如何实现循环处理数据

只看楼主收藏回复

刚完成了一个帖子了,有点累了。这个帖子直接上图或代码,加以注释吧。
这帖子和上一帖子均是由群内讨论而引发的。
首先是翠羽发了一个实现循环定时存档的代码。
以下,他发出来的初始数据,很简单,部分注释也是错误的,存档的功能也不一定能实现。
大家不要笑话,每个人都是这么过来的,包括当初的我。反而我们要勇于分享才是,有交流有讨论,才能更好更快的提高。
[ENABLE]
alloc(wqnm,32) //申请标签
createthread(wqnm) //注册全局变量
wqnm:
mov ecx,[gamesvr.exe+1CD9E4] //赋值ecx, 人物地址
push ecx
call gamesvr.exe+99C10 // 存档函数,此函数返回04 有一个实参
push #10000 // 时间
call sleep // 暂停执行一段时间
jmp wqnm
ret
[DISABLE]
dealloc(wqnm)


IP属地:广东1楼2022-11-12 23:09回复
    以下是我直接在原代码上的纠正
    [ENABLE]
    alloc(wqnm,32) //申请标签
    //上面的注释不正确,这是申请内存空间(存储代码,数据的地址)
    createthread(wqnm) //注册全局变量
    //上面的注释不正确,这是让系统在”游戏里“建立新线程,运行注入在wqnm的代码
    wqnm:
    mov ecx,[gamesvr.exe+1CD9E4] //赋值ecx, 人物地址
    push ecx
    call gamesvr.exe+99C10 // 存档函数,此函数返回04 有一个实参
    //调用函数的方式不可靠,上一帖子分析了一大堆,我给出结论,大意是:
    // 要正确调用函数 1,保证参数的正确性,2, 平衡好堆栈
    // mov ecx,[gamesvr.exe+1CD9E4] 这是读取存储在第1个位置的人物指针
    // 假如初登陆2个人物,下线第1个时,这时要用 mov ecx,[gamesvr.exe+1CD9E8]
    // 读取的地址要 +4 ,所以调用函数时,不能保证参数的正确性了
    push #10000 // 时间
    call sleep // 暂停执行一段时间
    jmp wqnm
    ret
    [DISABLE]
    dealloc(wqnm)


    IP属地:广东2楼2022-11-12 23:30
    回复
      下面是我改进的脚本
      [ENABLE]
      alloc(wqnm,32) //申请标签
      createthread(wqnm) //建立新线程,运行我们的代码
      wqnm:
      mov esi,gamesvr.exe+1CD9E0 //存储人物地址的前一个地址 -4
      xor edi,edi // 计数器 清0
      _loop_15: // 遍历所有人物的存储地址 共15个
      inc edi // edi 增加 1
      cmp edi,#16 // 比较edi的数据大小
      jnl _end_loop_15 // 1-15 读取数据 , 16时,跳出循环
      mov ecx,[esi+edi*4] // 按存储的序号读取人物地址
      test ecx,ecx // 判断读到的人物地址是否为0
      je _loop_15 // 无数据 为0
      push ecx // 不为0,则是有效人物地址,保证了存档参数的正确
      call gamesvr.exe+99C10 // 存档函数,此函数返回04 有一个实参
      jmp _loop_15 // 跳至下一循环
      _end_loop_15: // 循环结束
      push #10000 // 时间
      call sleep // 暂停执行一段时间
      jmp wqnm
      ret
      [DISABLE]
      dealloc(wqnm)


      IP属地:广东3楼2022-11-12 23:47
      回复
        3楼脚本仍然不够好,因为线程一运行,就无法停止
        如果你取消脚本的激活状态,线程就会出错了
        下面是我加了控制代码的脚本,同时演示了全局变量的定义,及其使用
        全局变量(标签) 即是能全部脚本能直接读写的地址,使用前不用重新定义
        脚本中,如果有新定义同名标签,会覆盖全局标签
        [ENABLE]
        globalalloc(DingShi_CunDang,32) //申请空间,并定义全局变量DingShi_CunDang
        // 标签 (地址)取一个容易记的名字是个好习惯,阅读和检查时更方便.
        // 这种定义成功后,无法更改空间大小,以及全局标签名称!
        label(_code) //定义新标签(地址) 默认是仅当前脚本有效
        label(flag_out)
        registersymbol(flag_out) // 注册成全局标签
        label(count_run)
        registersymbol(count_run) // 注册成全局标签
        createthread(_code) //建立新线程,运行我们的代码
        DingShi_CunDang:
        db 00 00 00 00 // 清0 占用 4个 byte (00)
        flag_out: // = DingShi_CunDang + 4 这地址是在代码之前
        db 00 00 00 00 // 清0 占用 4个 byte (00)
        _code: // 实际代码存储的地址,它 = DingShi_CunDang + 8
        mov eax,[flag_out]
        cmp eax,0
        jne _end // 其它脚本将地址 flag_out 改为非0时, 我们可以结束线程, 这是控制实现交互的代码.
        mov esi,gamesvr.exe+1CD9E0 //存储人物地址的前一个地址 -4
        xor edi,edi // 计数器 清0
        mov ebx,edi
        _loop_15: // 遍历所有人物的存储地址 共15个
        inc edi // edi 增加 1
        cmp edi,#16 // 比较edi的数据大小
        jnl _end_loop_15 // 1-15 读取数据 , 16时,跳出循环
        mov ecx,[esi+edi*4] // 按存储的序号读取人物地址
        test ecx,ecx // 判断读到的人物地址是否为0
        je _loop_15 // 无数据 为0
        push ecx // 不为0,则是有效人物地址,保证了存档参数的正确
        call gamesvr.exe+99C10 // 存档函数,此函数返回04 有一个实参
        inc ebx // 自增 1
        jmp _loop_15 // 跳至下一循环
        _end_loop_15: // 循环结束
        push #10000 // 时间
        call sleep // 暂停执行一段时间
        test ebx,ebx
        je _code // ebx 为0时,视为没有存档操作,无登陆人物
        mov [DingShi_CunDang],ebx // 记录实时在线人数,其它脚本可能有用
        mov eax,count_run
        inc [eax] // 存储 有效存档的次数, 自增1
        // inc [count_run] 也可以
        // mov ecx,[eax] ; inc ecx ; mov [eax],ecx 也可以
        jmp _code
        _end: //直接使用的地址,没有预先定义 label 不是个好习惯,有可能造成标签冲突(地址不正确)
        ret
        count_run: // 标签放这里, 表示地址在代码之后
        // 存储数据的标签,建议放在代码后面,这样容易调整
        db 00 00 00 00
        [DISABLE]
        // dealloc(DingShi_CunDang) 这是没用的,无法撤销空间了
        unregistersymbol(count_run) // 撤销全局标签,撤销后其它脚本还有访问就会出错


        IP属地:广东5楼2022-11-13 00:20
        回复
          激活运行上面脚本后,建立了3个全局标签(地址)
          其它脚本通过访问 DingShi_CunDang 即可获取到 在线人数(数据最大是10秒延迟)
          mov [flag_out],1 即可结束存档线程的
          [count_run] 这是读取执行存档次数的
          通过全局变量,我们就实现了脚本间数据交通
          但要注意,地址是按顺序"命名"的,所以 其它脚本里:
          mov [count_run+4], 01 也是使用全局变量的一种方式,用了偏移量来定位地址
          当然得考虑全局标签的定义的合理性, 像 mov [flag_out+4], 01 代码也能顺利执行,但会改写存档的代码!存档线程就会出错了.


          IP属地:广东6楼2022-11-13 00:33
          回复
            看不懂


            IP属地:新疆来自Android客户端7楼2022-11-13 08:54
            收起回复
              比较难学啊


              IP属地:浙江来自iPhone客户端8楼2023-01-14 22:13
              回复


                IP属地:辽宁9楼2023-01-15 17:18
                回复
                  我只能说吧主你太厉害了


                  IP属地:河南来自Android客户端10楼2023-01-16 20:56
                  回复
                    没有别的办法完善三楼的无法取消激活的问题吗?也是碰到了这个问题


                    IP属地:浙江11楼2023-01-29 22:01
                    回复
                      registersymbol注册一个全局标签,并且创建一个createthread线程后,如何在其他脚本中能检测这个全局标签是否可被调用(也就是没关),如果检测到不可调用(关闭了)就直接跳过call 线程?


                      IP属地:江苏12楼2023-09-29 08:59
                      收起回复
                        首先, 得是一名程序员


                        IP属地:四川13楼2023-11-18 19:20
                        收起回复
                          学到了,创建线程减少了对原有程序的侵入,很有用


                          IP属地:河南14楼2024-09-12 19:43
                          回复