Board logo

标题: [其他] 【第三方】CAPI 注入版【1.2 1D910】 [打印本页]

作者: defanive    时间: 2012-9-30 09:40     标题: 【第三方】CAPI 注入版【1.2 1D910】

第三方命令行工具 CAPI
让批处理调用API
Made By Defanive

11/04/12:更新1.2, Build 1D910, x32

目录
2L 开发手记
3L 第三方信息
4L 方法列表
5L 方法示例
6L 开发范例

http://bcn.bathome.net/s/tool/index.html?key=CAPI
作者: defanive    时间: 2012-9-30 09:40

本帖最后由 defanive 于 2012-11-5 04:21 编辑

开发手记

在非注入版CAPI的开发完成后,很多人提到了非注入版的缺陷
由于调用API之后进程被销毁,很多在进程内保存信息的API都无法正常使用
而且由于频繁打开新进程,调用API的效率降低了很多

于是注入版CAPI就在开发当中了
经过几个星期的开发,大约在6月底完成了CAPI 1.0版的开发
后续进行了几次修改,加入了COM调用功能,版本号改为1.1
这就意味着,支持COM功能的CAPI可以调用DirectX8了,也就是可以用批处理开发DX游戏等
还未进行过DX的调用测试,但是理论上应该是可以的

然后就这样搁置了几个月在我电脑里面
现在快10月份了,终于决定,不管BUG有多少,先发布出来再说

由于是注入版的,所以本身只能适用于32位的操作系统
因为dll是32位代码,所以无法注入到64位的cmd.exe进程中
但是,批处理可以判断自己是否在64位系统中,然后启动32位的cmd.exe,这样CAPI也可以运行在64位的系统中
没有测试环境,无法确定是否运行正常

免杀问题实在没办法怎么做,cmd.exe属于非常敏感的系统进程,基本上注入都很危险
尽量做到最好了,基本不怎么杀(360就算了,跟360玩免杀毫无意义)
因此想使用这个的开发者们,自己斟酌使用,有被杀的风险

用CAPI进行开发,个人感觉更考验的是对API的理解
CAPI除了API调用和COM调用和一些简单功能以外,本身并不带有任何其他功能
因此如果对API使用不熟,用CAPI也没办法做出特别超群的东西

暂时是这样,先发布1.1 Build 1D861
BUG反馈,建议等会帮助CAPI前进

————————————————————————————————————————

关于API可调用的回调函数,例如EnumWindows的回调,窗口消息的回调函数,有一个想法
最近学业甚忙,等到有时间了就开始做
简单的来说就是CAPI虚拟一个回调函数,然后虚拟的回调函数调用批处理
如果做成了的话,批处理就可以彻底的开发窗口程序了
也可以使用SetWindowsHookEx里面的Lower-Level Hooks,做键盘钩子和鼠标钩子
总之一切需要用到回调函数的都可以使用了
原理可用性大致确定,稳定性尚不清楚,有待测试
如果做好了就是一大进步,做不好就只能想其他办法了

————————————————————————————————————————

杯具试了一下结果不行,暂时没什么可以做的了

————————————————————————————————————————

更新1.1, Build 1D8B0, x32
对Inline API Hook进行了改进,改用新的方法提高效率
现在5000条set命令的执行耗时和无CAPI注入的耗时相差在1毫秒以内
基本上已经不影响set命令的执行效率了
另外一个重要的BUG修正,Mem Put命令的@标识符,现在可以正常的移动指针了
API Call增加了.标识符,可以传字节参数(目的是兼容cdecl函数)
CAPI.dll大小缩小了0.50KB

————————————————————————————————————————

更新1.2, Build 1D910, x32
把CAPI的调用方式分成两类,SetCall和GetCall
SetCall为旧版的"set CAPI=命令"的调用方式
GetCall为"%CAPI 命令%"的调用方式
对API调用时的dll加载做了优化,dll加载后不进行卸载,加速下一次使用dll的速度
作者: defanive    时间: 2012-9-30 09:40

本帖最后由 defanive 于 2012-11-5 04:24 编辑

第三方信息

CAPI.dll
1.2 Build 1D910 x32
8.00KB

CAPI.exe
2.29KB

在批处理开头需要调用一次CAPI.exe(无参数),同时CAPI.dll和CAPI.exe必须在同一目录下
调用完之后会将CAPI.dll注入到cmd.exe进程中
CAPI支持两种调用方法,GetCall和SetCall
默认情况下SetCall处于开启状态,GetCall处于关闭状态
SetCall调用方法是用set命令修改CAPI变量值完成的,如set "CAPI=Mem Alloc 8"
GetCall调用方法是用%(或!)查询变量名完成的,如%CAPI Mem Alloc 8%
CAPI_Ret变量储存执行的返回值
CAPI_Err变量储存调用API后GetLastError的返回值
这两个变量的内容请在命令执行完之后及时复制到其他变量
在GetCall中命令的变量会被解析成CAPI_Ret的值

注入版的最大优势在于只需要批处理开头调用一次CAPI.exe,往后任何调用都可以通过set命令完成
这样提高了CAPI的调用速度,同时让代码执行在cmd.exe进程中

现在最新的1.2版本支持GetCall的调用方式,更加接近于函数调用的语法
如开启GetCall后,代码echo %CAPI CAPIDll Ver%
就会先执行CAPI CAPIDll Ver,并把返回值作为变量值,实际执行了echo 1.2
作者: defanive    时间: 2012-9-30 09:41

[i=s] 本帖最后由 defanive 于 2012-11-5 04:25 编辑 [/i]

[b]命令列表[/b]

前置符号及意义:
.        1B        字节
:        2B        短整型
;        4B        长整型
#        -        字符串(ANSI)
$        -        字符串(Unicode)
*        4B        变量(的地址)
@        0B        移动指针,后跟欲移动的距离

这些前置符号往往用在参数里面,用于指定参数的类型和意义

接下来就是CAPI支持的命令列表:

Mem Alloc [sz]
在cmd.exe进程里面创建一块内存
注意,内存块使用完毕后需调用Mem Free释放,否则可能造成内存泄漏
参数:[sz]为欲创建的大小
返回值:创建的内存块的地址保存在CAPI_Ret变量里

Mem Free [addr]
释放cmd.exe进程里面的一块内存
注意,不要释放非自己创建的内存块,可能造成cmd.exe崩溃
参数:[addr]为欲释放的内存地址
返回值:无

Mem Put [s][addr] [s][data] [s][data] ...
将数据按格式写入内存地址中
注意,如果写入的数据量超过内存块大小,可能造成cmd.exe崩溃
参数:[s][addr]为欲写入内存地址,可以用“;内存地址”或者“*变量名”;[s][data]为欲写入的数据,[s]为前置符号,[data]为数据内容
返回值:无

Mem Copy [s][addr] [s][addr] [sz]
将源地址的一段内存复制到目标地址
注意,如果地址不可读或不可写,可能造成cmd.exe崩溃
参数:第一个参数[s][addr]为目标地址,第二个为源地址,都可以用“;内存地址”或者“*变量名”;[sz]为欲复制的内存块大小
返回值:无

Mem Print [s][addr] [s][var] [s][var] ...
将内存地址处的数据输出
注意,如果输出的数据量超过内存块的大小,可能造成cmd.exe崩溃
参数:[s][addr]为内存地址,可以用“;内存地址”或者“*变量名”,[s][var]为输出参数,[s]为输出的数据类型,[var]为输出的目标变量名
返回值:无

Var Fill [var] [char] [sz]
将变量填充为指定数量个指定字符
参数:[var]为目标变量名,[char]为字符,[sz]为字符数量
返回值:无

Var LenW [var]
返回变量的Unicode长度
参数:[var]为变量名
返回值:长度保存在CAPI_Ret变量里

Var LenA [var]
返回变量的ANSI长度
参数:[var]为变量名
返回值:长度保存在CAPI_Ret变量里

Var GetCall [Enable/Disable]
开启或关闭GetCall调用方式
参数:Enable或Disable
返回值:无

Var SetCall [Enable/Disable]
开启或关闭SetCall调用方式
参数:Enable或Disable
返回值:无

API Call [dll] [API] [s][data] [s][data] ...
调用API
参数:[dll]为dll路径,[API]为API函数全名,[s][data]为参数,[s]为参数标识(仅.;#$*可用),[data]为参数数据
返回值:API执行的返回值保存在CAPI_Ret变量里,API执行后的GetLastError返回值保存在CAPI_Err变量里

COM Init
初始化COM调用
注意,进行任何COM操作前必须调用本操作
参数:无
返回值:无

COM Create [data]
创建一个COM对象实例
注意,创建的对象实例在不需要使用时必须用COM Release释放
参数:[data]为COM对象名称
返回值:对象实例地址保存在CAPI_Ret变量里

COM Release [addr]
释放指定地址的对象实例
注意,创建任何对象之后都需要将对象释放;若对已释放的对象进行操作会导致cmd.exe崩溃
参数:[addr]为对象实例地址
返回值:无

COM Method [addr] [name] [s][data] [s][data] ...
调用对象实例的方法
参数:[addr]为对象实例地址,[name]为方法名称,[s][data]为参数,[s]为参数标识(仅;$可用),[data]为参数
返回值:方法的返回值保存在CAPI_Ret变量中

COM Get [addr] [name]
获取对象实例的属性
参数:[addr]为对象实例地址,[name]为属性名称
返回值:属性的值保存在CAPI_Ret变量中

COM Put [addr] [name] [s][data]
赋值对象实例的属性
参数:[addr]为对象实例地址,[name]为属性名称,[s][data]为数据,[s]为数据标识(仅;$可用),[data]为数据
返回值:无

CAPIDll Ver
获取CAPI.dll的版本号
参数:无
返回值:版本号保存在CAPI_Ret变量中

CAPIDll /?
打印CAPI.dll的信息
参数:无
返回值:无
作者: defanive    时间: 2012-9-30 09:41

本帖最后由 defanive 于 2012-11-5 04:25 编辑

方法示例

Mem Alloc与Free:
@echo off
CAPI
set "CAPI=Mem Alloc 4"
set "lpAddress=%CAPI_Ret%"
echo %lpAddress%
pause
set "CAPI=Mem Free %lpAddress%"
pause
创建了一块大小为4的内存,内存地址保存在lpAddress里
在批处理第一次暂停时,使用工具查看cmd.exe内存,可以看到在输出的地址处为4个空白字节的内存,第二次pause时,可以看到内存已经被释放

Mem Put:
@echo off
CAPI
set var=hello
set data=0123456789
set "CAPI=Mem Put *data .97 @1 :25105 #ab $ab *var"
echo %data%
pause
执行前data变量的内存内容为30 00 31 00 32 00 33 00 34 00 35 00 36 00 37 00 38 00 39 00
执行写入命令时,此时指针指向第1个字节,.97将1个字节为97写入,于是变成了61 00 31 00 ...,指针后移1位,指向第2个字节
@1将指针后移1位,此时指针指向第3个字节
:25105,此时指针指向第3个字节,将2个字节为25105写入,于是变成了61 00 62 11 32 00 ...,指针后移2位
#ab,此时指针指向第5位,将2个字节的ANSI字符串ab写入,于是变成了61 00 62 11 61 62 33 00 34 00 ...,指针后移2位
$ab,此时指针指向第7位,将4个字节的Unicode字符串ab写入,于是变成了61 00 62 11 61 62 61 00 62 00 ...,指针后移4位
*var,此时指针指向第11位,将var变量的内容全部写入

Mem Copy:
@echo off
CAPI
set var=hello
set data=0123456789
set "CAPI=Mem Copy *data *var 6"
echo %data%
pause
执行时,将var变量的前4个字节复制到data变量中,即是“hel”
因此输出“hel3456789”

Mem Print:
@echo off
CAPI
set var=0123456
set "CAPI=Mem Print *var .output_1 @2 :output_2 @1 #output_3 $output_4"
set output_
pause
var变量的内容为30 00 31 00 32 00 33 00 34 00 35 00 36 00
.output_1,此时指向第1个字节,将1字节的内容“31”放入output_1变量中,也就是48
@2,此时指针指向第2个字节,将指针后移2位,此时指针指向第4个字节
:output_2,此时指针指向第4个字节,将2字节的内容“00 32”放入output_2变量中,也就是12800
@1,此时指针指向第6个字节,将指针后移1位,此时指针指向第7个字节
#output_3,此时指针指向第7个字节,将接下来的内容作为ANSI字符串放入output_3变量中,也就是“33”,字符串3
$output_4,此时指针指向第9个字节,将接下来的内容作为Unicode字符串放入output_4变量中,也就是“34 00 35 00 36 00”,字符串456

Var Fill:
@echo off
CAPI
set data=test
set "CAPI=Var Fill data a 10"
echo %data%
pause
将data变量的内容以10个a覆盖,输出aaaaaaaaaa

Var LenW与LenA:
@echo off
CAPI
set data=我是Defanive
set "CAPI=Var LenW data"
echo %CAPI_Ret%
set "CAPI=Var LenA data"
echo %CAPI_Ret%
pause
LenW返回data变量的Unicode长度,也就是10
LenA返回data变量的ANSI长度,也就是12

API Call:
@echo off
CAPI
set "data=message"
set "CAPI=API Call user32 MessageBoxW ;0 *data $title ;1"
echo %CAPI_Ret%
pause
调用API MessageBox,第一个参数为0,第二个参数为data变量的地址,第三个参数为Unicode字符串title,第四个参数为1
由于CMD内部将变量data储存为Unicode,因此应使用Unicode版本的API,也就是MessageBoxW

COM(1):
@echo off
CAPI
set CAPI=COM Init
set CAPI=COM Create sapi.spvoice
set objSP=%CAPI_Ret%
set CAPI=Com Put %objSP% Rate ;5
set CAPI=Com Get %objSP% Volume
echo %CAPI_Ret%
set CAPI=Com Method %objSP% Speak $hello ;0
set CAPI=Com Release %objSP%
pause
等价于以下vbs代码
Set objSP=CreateObject("sapi.spvoice")
objSP.Rate=5
MsgBox objSP.Volume
objSP.Speak "hello",0
Set objSP=nothing

COM(2):
@echo off
CAPI
set CAPI=COM Init
set CAPI=COM Create scripting.filesystemobject
set objFSO=%CAPI_Ret%
set CAPI=COM Method %objFSO% OpenTextFile $1.txt ;1
set objTS=%CAPI_Ret%
set CAPI=COM Method %objTS% Skip ;2
set CAPI=COM Method %objTS% ReadLine
echo %CAPI_Ret%
set CAPI=COM Release %objTS%
set CAPI=COM Release %objFSO%
pause
等价于以下vbs代码
Set objFSO=CreateObject("scripting.filesystemobject")
Set objTS=objFSO.OpenTextFile("1.txt",1)
objTS.Skip 2
MsgBox objTS.ReadLine
set objTS=Nothing
set objFSO=Nothing

GetCall:
@echo off
CAPI
set CAPI=Var GetCall Enable
echo %CAPI CAPIDll Ver%
pause
等价于以下的SetCall调用代码:
@echo off
CAPI
set CAPI=CAPIDll Ver
echo %CAPI_Ret%
pause
作者: defanive    时间: 2012-9-30 09:41

开发范例

Dodge 躲避球
由于进程数据得以保存,我们现在可以进行非常完美的画面显示了
同时画面也可以达到很高的FPS
作者: defanive    时间: 2012-9-30 09:42

占楼待编辑
作者: cjiabing    时间: 2012-9-30 10:50

高深的学问,使用还得加强学习。
作者: cjiabing    时间: 2012-9-30 10:52

高深的学问,使用还得加强学习。
作者: ht河豚    时间: 2012-9-30 11:34

厉害,顶一下
作者: wc726842270    时间: 2012-9-30 13:09

很不错。对P和VBS都很好,只不过P时CMD窗口有时要处理一下
PS:在这里发表一下个人想法,对于解释型语言来说,用处并不是太宽。
作者: tms2010    时间: 2012-10-1 01:01

Win8 直接崩溃
作者: 3dnowex    时间: 2012-10-1 17:36

希望capi能支持x64的win7呀!
作者: defanive    时间: 2012-10-1 18:00

回复 11# wc726842270
API的话对于是不是解释性语言都是很大用处的
COM的话相信经常在VBS中用COM的同学都知道其强大
作者: defanive    时间: 2012-10-1 18:01

回复 12# tms2010
暂时没有兼容Win8的打算
作者: defanive    时间: 2012-10-1 18:02

回复 13# 3dnowex
理论上是可以兼容x64的,批处理只需要判断自己是在x64环境下运行,然后启动32位的cmd.exe就可以正常执行了
没有测试环境暂时无法验证
作者: 3dnowex    时间: 2012-10-1 19:16

谢谢啊!~因为上一个版本在win7x64上会报错~现在假期手上没有64位的机器,等过几天去试试~CAPI相当强大呀,cmd+CAPI几乎等于win32asm了~谢谢LZ~
作者: netbenton    时间: 2012-10-1 19:49

本帖最后由 netbenton 于 2012-10-1 19:50 编辑

很强大,实现的画面很不错,美中不足,那个范例在我这里运行有点慢,被金山报毒~并且直接K掉了,关掉杀软才能运行的。
作者: defanive    时间: 2012-10-2 09:39

回复 18# netbenton
其实按照大部分机器的运行速度FPS都可以达到100以上的(我的机子经常都是300多)
于是加入了FPS限制,把FPS限制在30左右
但是由于sleep的精度有限,有最小延迟,所以按照计算出来的结果慢的机器可能实际FPS在20左右
总之这部分是程序设计的问题,与CAPI效率没什么关系,CAPI速度是比一般的第三方调用快很多倍的

关于杀软的问题,金山我在做免杀的时候也注意到了
据说金山除了静态查杀还有动态的,动态查杀要过很难(像什么沙盒执行什么的就更加难过了)
所以金山大概以我个人的力量还暂时过不了,毕竟我只会码程序,免杀这些也就是知道点皮毛
总之杀软的问题,还是没什么解决方案,只能说“开发者斟酌使用”了
作者: cutebe    时间: 2012-10-2 11:42

我的一台电脑 XP 上能运行
而另一台 XP 则只有第一行有一个光标,闪阿闪没画面
作者: defanive    时间: 2012-10-2 11:49

回复 20# cutebe
没画面的应该是注入失败了
试一下在那台电脑上打开CMD,进入到CAPI的目录
然后执行CAPI,再执行set CAPI=CAPIDll /?
看一下有没有显示帮助信息
作者: cutebe    时间: 2012-10-2 14:45

本帖最后由 cutebe 于 2012-10-2 14:48 编辑

没有
========
复制到另一个目录又可以了,晕阿
原目录是在 “我的文档” 下,这个位置不行(再复制回去也不行)看来是位置关系。
作者: defanive    时间: 2012-10-3 04:05

回复 22# cutebe
没留意过我的文档的问题。。
作者: netbenton    时间: 2012-10-3 11:33

回复 19# defanive


    抓狂~为什么我的机子上只有 1 FPS!!!而CPU使用率达到了100%
作者: ht河豚    时间: 2012-10-3 14:37

啥时的机啊,我06年的都28fps
作者: ht河豚    时间: 2012-10-3 14:37

啥时的机啊,我06年的都28fps
作者: netbenton    时间: 2012-10-4 16:19

回复 26# ht河豚
AMD3200,单核2.2G的CPU,应该是不可能那么慢才对
作者: defanive    时间: 2012-10-5 06:22

回复 27# netbenton
我给你的那个去掉FPS限制的版本怎么样?
PS 貌似AMD都比较慢?我不是很清楚。。
作者: garyng    时间: 2012-10-5 10:13

这个版本的CAPI注入后会循环用GetEnvironmentVariable检测CAPI环境变量?
作者: defanive    时间: 2012-10-5 10:35

回复 29# garyng
不是,是Hook了SetEnvironmentVariable,所以每次set命令的时候都会执行我的函数,如果变量名是CAPI的话就会进行处理
作者: ht河豚    时间: 2012-10-5 12:38

回复 27# netbenton
我家双核2.5GHz,是不是你电脑空闲时时CPU本来就高??
作者: garyng    时间: 2012-10-5 14:23

回复 30# defanive

哦~我还想问为什么循环检测站的CPU还那么低呢,原来是用了hook!
Hook是用什么方法实现的啊?JMP跳转到自己的函数,还是IAT?
作者: garyng    时间: 2012-10-5 14:38

回复 19# defanive


Public Declare Function timeGetTime Lib "winmm.dll" Alias "timeGetTime" () As Long
作者: garyng    时间: 2012-10-5 14:51

还有就是 语法有点复杂
不适合新手学习啊。。
作者: netbenton    时间: 2012-10-5 16:57

本帖最后由 netbenton 于 2012-10-5 17:00 编辑

回复 31# ht河豚
空闲时不高,就是放电影也只有10%左右,是不是要双核以上才能运行留畅哦?
作者: lllsoslll    时间: 2012-10-5 19:58

本帖最后由 lllsoslll 于 2012-10-5 20:17 编辑

回复 18# netbenton

回复 1# defanive

doskey.exe,conset.exe 是如何做到免杀的? 远程线程注入是不是有些兴师动众,邪乎?
我把注意力放在 doskey.exe 和论坛的 conset.exe 的实现上,

感兴趣加入此贴讨论
http://www.bathome.net/thread-19036-1-7.html

这个远程线程注入不知道有什么特殊的地方,也许可以借鉴下:
http://www.codeproject.com/Artic ... t-Variables-of-Remo
作者: defanive    时间: 2012-10-6 08:20

回复 36# lllsoslll
修改其他进程的环境变量早已实现,无需注入也可以,CAPI的非注入版就使用的此方法
至于免杀我十分感兴趣,方法差不多不知为何他们可以做到
作者: 3dnowex    时间: 2012-10-8 20:52

本帖最后由 3dnowex 于 2012-10-8 21:08 编辑

实测win7x64下出错,0xc0000018
用lordpe修改.text区段标志为内存中可共享,修改.rdata区段标志位内存中可共享,可写入。至此capi在win7x64下注入成功。
因为win7x64下windows\system32\cmd.exe比win7x32下的大100多KB,貌似实现了一个转向功能,就是运行cmd.exe时候根据系统自动转入windows\syswow64\cmd.exe,此时会注入失败。单独使用win7x64的syswow64下的cmd.exe和win7x32下的system32\cmd.exe均可以注入成功。实测在reactos的cmd.exe中也可以注入成功。
作者: defanive    时间: 2012-10-9 06:04

回复 38# 3dnowex
我的意思就是这样,批处理要判断自己是不是在x64环境下
如果是的话,批处理需要自己启动WOW64下的cmd.exe,这时候才是32位进程,才可以注入
作者: defanive    时间: 2012-10-9 10:54

更新:1.1, Build 1D8B0, x32
作者: defanive    时间: 2012-10-9 10:55

回复 32# garyng
修改函数头的JMP跳转
作者: garyng    时间: 2012-10-9 11:29

回复 41# defanive


   这种方法不会漏钩子么?
作者: defanive    时间: 2012-10-9 11:34

回复 42# garyng
不会,怎么会呢?
执行API都是把代码跳转到API的代码处执行,我把API的代码改成了JMP到我的函数
因此只要是调用API都会JMP到我的函数
作者: garyng    时间: 2012-10-9 11:47

回复 43# defanive

当调用HOOKED API时,就会jmp到自定义函数,当自定义函数处理玩后,就会把Api恢复,然后就返回,
可是在恢复api时刚刚好别的线程调用怎么办?


但是,cmd下应该不会发生这种事吧,毕竟是单线程的
作者: defanive    时间: 2012-10-9 11:56

回复 44# garyng
我的方法比较巧妙,不需要恢复API
原理很简单,仔细研究一下API的函数头就知道了
而且你说的也对,CMD是单线程的,不会出现这种情况
我的方法只是为了提高速度而已
作者: garyng    时间: 2012-10-9 21:17

回复 45# defanive


    跳到自定义函数后ret? 求解释啊
作者: defanive    时间: 2012-10-10 03:56

回复 46# garyng
嗯都是这样的,不是么
作者: garyng    时间: 2012-10-10 12:10

回复 47# defanive


    我用的是笨方法啊,又学一招了,谢谢!
作者: 3dnowex    时间: 2012-10-11 20:42

求助一下这种方式为何内存会出现读取错误?
  1. @echo off
  2. ..\CAPI
  3. set CAPI=COM Init
  4. set CAPI=COM Create InternetExplorer.Application
  5. set obj=%CAPI_Ret%
  6. set CAPI=COM Method %obj% Navigate $about:blank
  7. set CAPI=COM PUT %obj% Visible ;1"
复制代码
执行obj.navigate("about:blank")时内存出错
作者: defanive    时间: 2012-10-12 07:04

回复 49# 3dnowex
这个比较奇怪,我试了一下,IE对象的其他方法和属性调用都正常
但是Navigate和Navigate2调用会导致崩溃
原因暂时不明,正在研究中
作者: 3dnowex    时间: 2012-10-12 17:31

回复 50# defanive
在想bat是否能联合vbs通过这种方法做界面。
capi如果能自带一个调用函数,把其地址传给RegisterClass的参量WNDCLASS的lpfnWndProc,系统执行这个窗口消息处理函数的时候即跳入capi的内函数,capi开一个cmd新线程,将主动权bat指定的函数,执行到goto :EOF再次返回capi的内函数随后返回系统←不知这样是否可行呢?
作者: defanive    时间: 2012-10-13 09:07

回复 51# 3dnowex
这正是我在开发手记里面说的那个想法,结果是失败了
一切都做得很正常,但是唯一的问题在于,新线程返回到旧的执行点的时候,会有问题
CMD不是用独立的内存保存批处理代码执行位置的,也就是说新线程的批处理代码执行位置会把旧线程的位置代替掉
所以说杯具了,尽管调用了新线程,但是没办法返回到之前执行的位置
PS 有另外一个新想法,正在试验中
作者: netbenton    时间: 2012-10-13 11:42

本帖最后由 netbenton 于 2012-10-13 11:56 编辑

有个提议,语法能不改成这样:
set /capi 返回变量名1=[功能] [参数1] [参数2]…… [参数N]<行结束符>  返回变量名2=[功能] [参数1] [参数2]…… [参数N]<行结束符>   返回变量名3=[功能] [参数1] [参数2]…… [参数N]<行结束符> …………返回变量名N=[功能] [参数1] [参数2]…… [参数N]<行结束符>

PS:
1.也就是返回值直接存到指定变量,并且,一个set /capi 执行了多行capi命令~;
这样不但可以提速,有些情况还可以免受干扰,对需要多个api调用才能成完成的功能,更是有利
甚至“返回变量名2” 做成可以直接是用户的内存地址,即有些临时的api调用,没必要存到cmd 的环境变量。

2.如果某个调用语句很长时用变量,拼接法即可:

set 语句= 返回变量名1=[功能] [参数1] [参数2]…… [参数N]<行结束符>
set 语句=%语句% 返回变量名2=[功能] [参数1] [参数2]…… [参数N]<行结束符>
set 语句=%语句% 返回变量名3=[功能] [参数1] [参数2]…… [参数N]<行结束符>
……
set /capi %语句% 返回变量名N=[功能] [参数1] [参数2]…… [参数N]<行结束符>
作者: ht河豚    时间: 2012-10-13 12:34

netbenton的想法很好的说,但是如果set 的字串太多,也会影响效率的吧
作者: defanive    时间: 2012-10-14 05:28

回复 53# netbenton
我很喜欢返回变量名的想法,但是暂时似乎没有办法做到
set语句的处理是在cmd内部进行的,处理完最后再调用SetEnvironmentVariableW
所以除非有办法找到处理set的代码位置,不然都没办法做任何处理
对于多行命令同时执行的话,我认为没什么必要
这种多个命令同时执行是普通第三方遗留下来的传统
普通的第三方是启动新进程,因此启动进程的时间远远大于实际执行代码的时间
所以说把多行代码合并在一起就可以省去启动进程的时间
但是CAPI是基于注入的,所以说实际上跳转到钩子函数的耗时基本上非常少(我本机测试,20000条set命令,加了钩子只比不加钩子慢了0.06s)
所以说这样对速度的提升并没有很显著的效果
直接set CAPI=xxx&set CAPI=yyy基本上就可以做到一样了(虽然看起来稍微难看一点)
返回变量名是一个很好的想法,以为很直接的省去了set xxx=%CAPI_Ret%这一行命令
但是杯具的是貌似没办法做成set /CAPI ret_var=xxx的语法
最多可以做成set CAPI=ret_var xxx,但是这样大改语法结构了
总之谢谢建议,对于CAPI的语法调用问题我还是觉得很蛋疼,已经尽量尝试做到最好了
目前大致的结构是set CAPI=[主类] [子类] [标识符][参数1] [标识符][参数2] ...
将命令分成主类和子类是为了减少程序员的记忆量,也让代码容易阅读
作者: 3dnowex    时间: 2012-10-14 13:26

回复 55# defanive
新手od断ReadConsole跟了下XP的cmd.exe下运行set /a,发现进入到4AD05A42处的内函数中有个字符串的比较(/a /p),这里是否能做些手脚实现set /capi或者set /c这样的功能呢?
作者: defanive    时间: 2012-10-14 14:50

回复 56# 3dnowex
麻烦的在于不同版本的cmd函数地址也不一样,不方便做判断
cmd没有一个开放给外界的接口,很蛋疼 = =
感觉走到最后都只能走回API Hook的路上
作者: defanive    时间: 2012-11-5 04:27

更新:1.2, Build 1D910, x32
作者: caruko    时间: 2012-11-8 16:14

强!!
之前看到你的CAPI,就希望谁能做个 注入版,没想到真出来了
而且这么强大!!
作者: jains521    时间: 2012-11-19 15:15

.很强大 ...有没有开源.
作者: junmt    时间: 2012-11-29 22:59

支持~~顶顶~~~安心大巴
作者: ht河豚    时间: 2012-11-30 20:38

有教程么??本人压根不知API
作者: zhangzsky    时间: 2015-6-14 12:15

回复 58# defanive


    已经很久没更新,新的系统希望可以支持下,毕竟win8,8.1,10都开始普及了
希望可以兼容8.1或10
作者: tmplinshi    时间: 2015-11-25 14:57

defanive 发表于 2012-9-30 09:40
但是,批处理可以判断自己是否在64位系统中,然后启动32位的cmd.exe,这样CAPI也可以运行在64位的系统中
没有测试环境,无法确定是否运行正常


win7 64 位系统用 32 位 cmd.exe 无法运行。
作者: l200541075    时间: 2017-1-12 09:09

高手啊,下载来学习一下,感谢分享!
作者: l200541075    时间: 2017-1-12 09:24

回复 64# tmplinshi
确实无法使用,打开CAPI报错




欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2