找回密码
 注册
搜索
系统gho:最纯净好用系统下载站投放广告、加入VIP会员,请联系 微信:wuyouceo
查看: 79|回复: 4

办公软件WPS的JSA中读取/写入内存数据

[复制链接]
发表于 3 小时前 | 显示全部楼层 |阅读模式
表格:通过ExecuteExcel4Macro调用WinAPI实现

函数:

  1. function 数据入内存(数组缓冲){        //返回内存句柄
  2.         const 数据操作=new DataView(数组缓冲);
  3.         const 总字节=数组缓冲.byteLength;
  4.         let 偏移=i=0,待写数据=[],写入字节=[];
  5.         while(总字节>偏移){
  6.                 if(总字节-偏移>=4){待写数据[i]=数据操作.getInt32(偏移,true);写入字节[i]=4;i++;偏移+=4;}
  7.                 else{if(总字节-偏移>=2){待写数据[i]=数据操作.getInt16(偏移,true);写入字节[i]=2;i++;偏移+=2;}
  8.                 else{if(总字节-偏移==1){待写数据[i]=数据操作.getInt8(偏移,true);写入字节[i]=1;i++;偏移++;}}}
  9.         }
  10.         const 执行宏调用=ExecuteExcel4Macro;
  11.         const 内存句柄=执行宏调用(`CALL("Kernel32","GlobalAlloc","JJJ",${0x42},${总字节})`);
  12.         if(内存句柄){        //申请内存空间,会返地址
  13.                 const 内存地址=执行宏调用(`CALL("Kernel32","GlobalLock","JJ",${内存句柄})`);
  14.                 for(偏移=i=0;i<写入字节.length;i++){        //库Kernel32.dll和NtDll.dll里都有RtlMoveMemory
  15.                         执行宏调用(`CALL("Kernel32","RtlMoveMemory","2JNJ",${内存地址+偏移},${待写数据[i]},${写入字节[i]})`);        //写入
  16.                         偏移+=写入字节[i];
  17.                 }
  18.                 执行宏调用(`CALL("Kernel32","GlobalUnlock","JJ",${内存句柄})`);        //解锁全局内存对象
  19.                 return 内存句柄;        //返回
  20.         }else{console.log("未能分配内存!");}
  21. }
  22. function 内存取数据(内存句柄){        //返回数组缓冲
  23.         const 执行宏调用=ExecuteExcel4Macro;
  24.         const 总字节=执行宏调用(`CALL("Kernel32","GlobalSize","JJ",${内存句柄})`);        //内存对象空间大小
  25.         let 偏移,i,读取字节=[],读出数据;
  26.         for(偏移=i=0;偏移<总字节;i++){
  27.                 if(总字节-偏移>=4){读取字节[i]=4;偏移+=4;}
  28.                 else{if(总字节-偏移>=2){读取字节[i]=2;偏移+=2;}
  29.                 else{if(总字节-偏移==1){读取字节[i]=1;偏移++;}}}
  30.         }
  31.         const 数组缓冲=new ArrayBuffer(总字节);        //用于存储读出的数据
  32.         const 数据操作=new DataView(数组缓冲);
  33.         const 内存地址=执行宏调用(`CALL("Kernel32","GlobalLock","JJ",${内存句柄})`);
  34.         if(内存地址){        //var 文本=执行宏调用(`CALL("Kernel32","lstrcpynW","FFJJ","",${内存地址},${127})`);
  35.                 for(偏移=i=0;偏移<总字节;i++){
  36.                         读出数据=执行宏调用(`CALL("Kernel32","RtlMoveMemory","1NJJ",${内存地址},${内存地址+偏移},${读取字节[i]})`);        //读出
  37.                         if(读取字节[i]==4){数据操作.setInt32(偏移,读出数据,true);偏移+=4;}
  38.                         else{if(读取字节[i]==2){数据操作.setInt16(偏移,读出数据,true);偏移+=2;}
  39.                         else{if(读取字节[i]==1){数据操作.setInt8(偏移,读出数据,true);偏移++;}}}
  40.                 }
  41.                 执行宏调用(`CALL("Kernel32","GlobalUnlock","JJ",${内存句柄})`);        //解锁内存对象,以释放资源
  42.                 return 数组缓冲;        //返回
  43.         }else{console.log("未找到内存地址!");}
  44. }
复制代码



测试函数:
  1. function 数据字符串内存读写联合测试(){
  2.         const 执行宏调用=ExecuteExcel4Macro;
  3.         let 字符串="ABCD123";        //7字节字符串,需要8字节空间
  4.         const 字符串内存句柄=字符串到内存(字符串);        /*****写入字符串*****/
  5.        
  6.         console.clear();
  7.         let 取得字符串=内存取字符串(字符串内存句柄);        /*****读取字符串*****/
  8.         console.log("直接读字符串:"+取得字符串+"\t结束!");
  9.        
  10.         let 数据数组缓冲=内存取数据(字符串内存句柄);        /*****读取数据*****/
  11.         显示数组缓冲(数据数组缓冲);        /*****显示数据*****/
  12.         执行宏调用(`CALL("Kernel32","GlobalFree","JJ",${字符串内存句柄})`);        //释放内存
  13.        
  14.         let 数组缓冲=new ArrayBuffer(0x30);        //准备数据
  15.         let 数据操作=new DataView(数组缓冲);
  16.         数据操作.setInt32(0,0x34333231,true);        //小端序4321
  17.         数据操作.setInt32(4,0x38373635,true);
  18.         数据操作.setInt32(8,0x3039,true);
  19.         数据操作.setInt32(0x10,0x44434241,true);        //小端序DCBA
  20.         数据操作.setInt32(0x14,0x48474645,true);
  21.         数据操作.setInt32(0x18,0x4C4B4A49,true);
  22.         数据操作.setInt32(0x1C,0x504F4E4D,true);
  23.         数据操作.setInt32(0x20,0x54535251,true);
  24.         数据操作.setInt32(0x24,0x58575655,true);
  25.         数据操作.setInt32(0x28,0x5A59,true);
  26.        
  27.         let 数据内存句柄=数据入内存(数组缓冲);        /*****写入数据*****/
  28.        
  29.         let 取出字符串=内存取字符串(数据内存句柄);        /*****读取字符串*****/
  30.         console.log("数据取成字符串:"+取出字符串+"\t结束!");
  31.        
  32.         let 取出数组缓冲=内存取数据(数据内存句柄);        /*****读取数据*****/
  33.         显示数组缓冲(取出数组缓冲);        /*****显示数据*****/
  34.        
  35.         执行宏调用(`CALL("Kernel32","GlobalFree","JJ",${数据内存句柄})`);        //释放内存
  36. }
  37. function 显示数组缓冲(组缓冲){
  38.         const 数据操作=new DataView(组缓冲);        //操作对象
  39.         let 字节数据,高位,低位,数据=[],字符=[],数据串=字符串='';
  40.         let 四分隔,八分隔,十六分隔;
  41.         for(let i=0;i<组缓冲.byteLength;i++){
  42.                 if((i+1)%16==0){十六分隔='\n';}else{十六分隔='';}
  43.                 if((i+1)%8==0){八分隔=' ';}else{八分隔='';}
  44.                 if((i+1)%4==0){四分隔=' ';}else{四分隔='';}
  45.                 字节数据=数据操作.getInt8(i);
  46.                 高位=(字节数据>>>4&0xF).toString(16).toUpperCase();
  47.                 低位=(字节数据&0xF).toString(16).toUpperCase();
  48.                 数据[i]=高位+低位;
  49.                 数据串+=数据[i]+' '+四分隔+八分隔+十六分隔;
  50.                 if(!字节数据){字符[i]=' ';}else{字符[i]=String.fromCharCode(字节数据);}
  51.                 字符串+=字符[i]+' ';
  52.         }
  53.         console.log("数据串:\n"+数据串+"\n字符串:"+字符串+'\n');
  54. }

  55. function 字符串到内存(字符串){        //返回内存句柄
  56.         const 执行宏调用=ExecuteExcel4Macro;
  57.         let 分段文本=[],分段字节=[],总字节=0,段长度=127;        //可申请256字节内存,结束符1字节,汉字最长127
  58.         for(let 起始=i=0;起始<字符串.length;起始+=段长度,i++){
  59.                 分段文本.push(字符串.slice(起始,起始+段长度));
  60.                 分段字节.push(分段文本[i].replace(/[^\x00-\xff]/g,'xx').length);        //一个汉字占两个字节
  61.                 总字节+=分段字节[i];
  62.         }        //分配内存        //分配GlobalAlloc对应销毁GlobalFree        //分配GlobalAlloc对应销毁GlobalFree
  63.         const 内存句柄=执行宏调用(`CALL("Kernel32","GlobalAlloc","JJJ",${2},${总字节+1})`);
  64.         if(内存句柄){        //内存分配成功,然后锁写解内存。        //锁定内存对象,会返回其地址
  65.                 const 内存地址=执行宏调用(`CALL("Kernel32","GlobalLock","JJ",${内存句柄})`);
  66.                 for(let 偏移字节=i=0;i<分段文本.length;i++){        //字符串(JS变量)分批复制到刚申请的内存中。分批是因为有限长
  67.                         执行宏调用(`CALL("Kernel32","lstrcpynW","JJFJ",${内存地址+偏移字节},"${分段文本[i].replace(/\"/g,'\"\"')}",${分段字节[i]})`);
  68.                         偏移字节+=分段字节[i];        //返回地址J。        //字符串中两个双引号解释成一个(VB语法)
  69.                 }
  70.                 执行宏调用(`CALL("Kernel32","GlobalUnlock","JJ",${内存句柄})`);        //解锁内存对象,以释放资源
  71.                 return 内存句柄;
  72.         }else{console.log("未能分配内存!");}
  73. }
  74. function 内存取字符串(内存句柄){        //返回字符串
  75.         const 执行宏调用=ExecuteExcel4Macro,段长度=127;
  76.         const 内存地址=执行宏调用(`CALL("Kernel32","GlobalLock","JJ",${内存句柄})`);        //锁定,获取内存地址
  77.         if(内存地址){
  78.                 const 总字节=执行宏调用(`CALL("Kernel32","lstrlenA","JJ",${内存地址})`);        //内存文本字节数
  79.                 let 偏移字节=0,文本字符串=分段文本='';
  80.                 while(偏移字节<总字节){        //返回字符串F。        //返回超255字节时,也需要分段操作
  81.                         分段文本=执行宏调用(`CALL("Kernel32","lstrcpynW","FFJJ","",${内存地址+偏移字节},${段长度})`);
  82.                         //偏移字节+=执行宏调用(`CALL("Kernel32","lstrlenA","JC","${分段文本.replace(/["\n]/g,'x')}")`);
  83.                         偏移字节+=分段文本.replace(/[^\x00-\xff]/g,'xx').length;        //计算字符串字节数
  84.                         文本字符串+=分段文本;
  85.                 }        //解锁内存对象,以释放资源
  86.                 执行宏调用(`CALL("Kernel32","GlobalUnlock","JJ",${内存句柄})`);
  87.                 return 文本字符串;
  88.         }else{console.log("未找到内存地址!");}
  89. }
复制代码


发表于 2 小时前 | 显示全部楼层
这是什么了

点评

暂时没想到有什么用。也许可以查看注册函数执行后的数据。  详情 回复 发表于 2 小时前
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层
感谢分享!
回复

使用道具 举报

 楼主| 发表于 2 小时前 | 显示全部楼层

暂时没想到有什么用。也许可以查看注册函数执行后的数据。
回复

使用道具 举报

发表于 1 小时前 | 显示全部楼层
感谢分享!
回复

使用道具 举报

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

本版积分规则

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1|闽公网安备35020302032614号 )

GMT+8, 2026-4-12 20:16

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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