dllcall ,用批处理做程序
dllcall 类似于 rundll32 的程序,但是调用很明了,实现方式也和 rundll32 不同,rundll32 可以为一些API提供窗口,dllcall 只是一个命令行(console pro)程序,所以 rundll32 应用最广的调用.cpl文件的执行在dllcall中不能实现。dllcall 主要用来扩展批处理,可以用批处理做一些简单的程序。
dllcall 的制作缘起主要是由于作者以前一直在用 NSIS 将一些工具打包放在移动设备中用来部署工作环境,但移动设备中的exe文件经常会被病毒感染,而且当工具包有一点小改动时也要重新编译整个包,当这个包很大时就很耗费时间,所以改用批处理加 7za 加单独压缩的包的形式,shorcut 也是这个原因制作的。
dllcall的特点:
- 使用汇编语言编写,fasm汇编器汇编,指令级优化,极小的体积(目前版本4KB),超快的速度,真正意义上的绿色软件。
- 开源软件,使用MIT开源协议发布,可以了解程序的每一个细节,放心地使用(可惜360之类的很多杀毒软件会报毒,汇编语言写的程序命运大都如此吧)。
- 提供的只是一种机制,而非功能,从而随心所欲地实现自己想要的功能,而且仅仅是通过批处理。
- 由于涉及到Windows API的调用,可能有些拗,其实编程很简单,很多人大抵是被课堂里的C语言给震慑了吧,用dllcall做程序,首先需知道自己想要什么功能,批处理能否实现(GUI界面当然不是命令行程序所擅长的),涉及到複雜結構體的填充,多個指針的調用,及上下函數傳遞參數非常複雜的情況不宜用dllcall。其实通过调用一两个API函数实现的功能最适合dllcall了,一些例子就在下面。
dllcall使用教程看这里。- Usage: dllcall {function name} [parameter(s)]... {DLL name}
-
- Examples:
-
- dllcall Sleep,1000,kernel32.dll
-
- dllcall MessageBoxA,,"Hello world!",Prompt,1,user32.dll
-
- dllcall MessageBoxW,,"%uAdd prefix %u indicate unicode s ",%ua,1,user32.dll
-
- dllcall ShellExecuteA,,,"http://www.google.com",,,,shell32.dll
-
- dllcall 61,,,,,,shell32.dll
-
- dllcall 61,,,,%uRun,"%u Only Demo",,shell32.dll
-
- dllcall SendMessageA,0x0FFFF,0x00112,0x0F170,1,user32.dll
-
- the display is going to low power.
-
- dllcall SHChangeNotify,0x8000000,0x1000,,,shell32.dll
-
- refresh desktop items.
复制代码
使用%u前缀指明后面跟的是unicode字符串,原因是所有与字符有关的API都有ansi及unicode两种版本,其函数后面有A及W字符,如MessageBoxA和MessageBoxW,而系统默认的字符编码是unicode,所以在给一些用序号导出的API传递字符串参数时只能在调用时实现编码的转换,shell32.dll中序号为61的函数就是这种情况。
用%o使用一个输出型参数,每次调用只能有一个%o出现,%o输出的结果在返回值之后,如dllcall GetWindowsDirectoryA,%o,4096,kernel32.dll ,输出结果为 10 C:\WINDOWS 。%od将输出转换为一整数 调用函数的返回值回显为一个十进制的数。
2009-12-29 更新:
考虑再三,还是加上了多个函数的调用,如 dllcall OpenClipboard,,user32.dll;GetClipboardData,1,user32.dll*;CloseClipboard,user32.dll- 这样的格式,”*”指明返回值是一个指向字符串的指针。
文档及源码整理得不太好,故文档不再放出,源码暂不放出。
每个DLL导出的函数可用 gie 获取,在这里下载,如用 gie -e shell32.dll 得到 shell32.dll 的所有导出函数,API的调用说明参见MSDN,也可在这里找到相关的资源。
- “,”(即英文逗号)分隔传入的参数,在参数中使用英文逗号,用”\”转义,如”Hello\,i am tom.”这样的参数。逗号会被空格代替,参数可以是纯数字,如1234或”1234″,表示一个十进制的数; 0x 开头的参数表示一个十六进制的数,如0×1234或”0×1234″;
- %u 开头的参数表示这是一个unicode 类型的字符串,如%uHello\,man 或”%uHello\,i am tom.”;
- %o 开头的参数表示将这个参数中的结果打印出来,如%o 或”%o”,
- %od 开头的参数与 %o 开头的参数类似,也是打印结果,但是会认为参数是一个整数,用法与%o 相同,如果不全是数字而且没有
- 0x %u 等参数说明符,参数会被认为是一个字符串。 参数中有空格或中文字符,用引号将参数引起来,0x %u 等参数说明符号应在引号内,如果传入的参数值为0,可用,,这样的写法。
1.0.3.0版本加入功能说明: 加入%r参数说明符,加入符号”;”、”*”、”-”,增加了多个函数的调用。 %r用来引用一次dllcall使用中上一个函数的返回值; “;”用来分隔调用的函数,在函数中使用”;”用”\;”转义,”*”及”-”放在一个函数调用语句的后面,”*”用来指示函数的返回值是一个字符串的地址,”-”用来指示函数的返回值不再打印出来。例如:- dllcall OpenClipboard,,user32.dll;GetClipboardData,1,user32.dll*;CloseClipboard,user32.dll-
复制代码
这个语句中有3个函数,第一个函数打开剪切板,第二个函数取得其中的数据,第三个函数关闭了剪切板。
2010-6-21 更新:
1.0.3.3版本加入功能说明: 加入%p参数说明符。 %p指出这个参数是一个指针,其后可跟一个十进制或十六进制的数对其赋初值。例如:- dllcall IsNetworkAlive,%p0x1,sensapi.dll
复制代码
这个语句中传入IsNetworkAlive的参数是一个指针(即地址值),这个地址中的内容是1 。
2010-7-17 更新:
1.0.3.4版本加入功能说明: 加入”-r”选项。 由于Windows的命令解释器cmd.exe的for命令中使用dllcall会出错,所以”-r”选项的作用就是给出一个替代”,”的字符,如:- for /f %i in ('dllcall -r# MessageBoxA##"test"#p#0x24#user32.dll') do set return=%i
复制代码
源码及可執行文件下載: http://vinoca.org/download
示例1: 对 notepad 操作- @echo off
- start "" notepad.exe
- dllcall Sleep,700,kernel32.dll-
- dllcall FindWindowA,"Notepad",,user32.dll-
- set hPad=%errorlevel%
- dllcall ShowWindow,%hPad%,3,user32.dll-
- dllcall FindWindowExA,%hPad%,,"Edit",,user32.dll-
- set hEdit=%errorlevel%
- call:putchar 0x4F
- call:putchar 0x6E
- call:putchar 0x6C
- call:putchar 0x79
- call:putchar 0x2C 900
- call:putchar 0x08
- call:putchar 0x20
- call:putchar 0x44
- call:putchar 0x45
- call:putchar 0x4D
- call:putchar 0x4F
- call:putchar 0x2E
- call:sleep 1500
- rem 发送 WM_QUIT(0x12) 消息到notepad的主窗体,关闭notpead .
- dllcall PostMessageA,%hPad%,0x12,,,user32.dll-
- pause
-
- :putchar <char>
- setlocal
- set arg2=%2&&if "%2" == "" set arg2=300
- rem 发送WM_CHAR(0x102)消息到notepad的子窗体edit ,输入一个字符,wParam 参数为字符
- dllcall SendMessageA,%hEdit%,0x102,%1,,user32.dll-
- call:sleep %arg2%
- exit /b
-
- :sleep <ms>
- dllcall Sleep,%1,kernel32.dll-
- exit /b
复制代码
示例2: 关闭显示器- @echo off
- rem invoke SendMessage,HWND_BROADCAST,WM_SYSCOMMAND,SC_MONITORPOWER,1
- rem 使显示器处于低功耗状态
- rem dllcall SendMessageA,0x0FFFF,0x00112,0x0F170,1,user32.dll
- rem invoke SendMessage,HWND_BROADCAST,WM_SYSCOMMAND,SC_MONITORPOWER,2
- rem 关闭显示器
- dllcall SendMessageA,0x0FFFF,0x00112,0x0F170,2,user32.dll
复制代码
示例3: 修改“开始”按钮的文字(WinXP)- @echo off
- for /f %%i in ('dllcall -r# FindWindowA#"Shell_TrayWnd"##user32.dll') do set hWindow=%%i
- for /f %%i in ('dllcall -r# FindWindowExA#%hWindow%##"Button"##user32.dll') do set hWindow=%%i
- rem 发送WM_SETTEXT 消息到子窗体
- dllcall SendMessageA,%hWindow%,0x0C,,"傳送",user32.dll-
- exit
复制代码
示例4: 隐藏批处理窗体及播放wav格式音频文件- @echo off
- set cmdTitle=cmd%random%
- title %cmdTitle%
- for /f %%i in ('dllcall -r# FindWindowA##%cmdTitle%#user32.dll') do set hCmd=%%i
- rem 隐藏窗口1秒
- dllcall ShowWindow,%hCmd%,,user32.dll-
- dllcall Sleep,1000,kernel32.dll-
- dllcall ShowWindow,%hCmd%,1,user32.dll-
- rem 播放 WAV 格式声音
- dllcall PlaySoundA,"type.wav",,0x20000,winmm.dll-
- pause
复制代码
示例5: 打开关闭光驱仓门- @echo off
- dllcall mciSendStringA,"open cdaudio",,,,winmm.dll-
- ::打开光驱仓门
- dllcall mciSendStringA,"set cdaudio door open",,,,winmm.dll-
- ::关闭光驱仓门
- ::dllcall mciSendStringA,"set cdaudio door closed",,,,winmm.dll-
- dllcall mciSendStringA,"close cdaudio",,,,winmm.dll-
- pause
复制代码
示例6: 打开可移动存储设备- @echo off
-
- set n=1
- :loop
- if %n%==12 goto endloop
- for /f "tokens=%n% delims=," %%i in ("C:,D:,E:,F:,E:,H:,I:,J:,K:,L:,M:,N:") do set driveString=%%i
- for /f %%i in ('dllcall -r# GetDriveTypeA#%driveString%#kernel32.dll') do set driveType=%%i
- if %driveType%==2 start "" "%driveString%"
- set /a n+=1
- goto loop
- :endloop
- pause
复制代码
示例7: MessageBox 演示- @echo off
-
- set strPrompt=演示
- ::dllcall Beep,5000,50,kernel32.dll
- ::dllcall MessageBeep,0x20,user32.dll
- dllcall MessageBoxA,,"你好",%strPrompt%,,user32.dll-
- for /f %%i in ('dllcall -r# MessageBoxA##"喜欢用批处理吗?"#%strPrompt%#0x24#user32.dll') do set return=%%i
- if %return%==6 dllcall MessageBoxA,,"我也很喜欢哦。",%strPrompt%,0x30,user32.dll-
- if %return%==7 dllcall MessageBoxA,,"Oh ,No!",%strPrompt%,0x10,user32.dll-
- pause
复制代码
示例8: 命令行显示剪切板中文字数据- dllcall OpenClipboard,,user32.dll;GetClipboardData,1,user32.dll*;CloseClipboard,user32.dll-
复制代码
示例9: 设置屏幕字体的边缘平滑- dllcall SystemParametersInfoA,75,1,0,3,user32.dll-
- dllcall SystemParametersInfoA,8203,0,2,3,user32.dll-
- dllcall SystemParametersInfoA,8211,0,1,3,user32.dll-
- dllcall SystemParametersInfoA,8205,0,1000,3,user32.dll-
- dllcall RedrawWindow,0,0,0,1927,user32.dll-
复制代码
示例10: 测试网络是否可用- dllcall IsNetworkAlive,%p0x1,sensapi.dll
- :: 返回1可用,返回0不可用。
复制代码
示例11: 模拟键盘按键- start "" notepad.exe
- for /f %%i in ('dllcall -r# FindWindowA#"Notepad"##user32.dll') do set hPad=%%i
- dllcall ShowWindow,%hPad%,3,user32.dll-
- dllcall Sleep,1000,kernel32.dll-
- ::发送Alt+H 按键
- dllcall PostMessageA,%hPad%,0x104,0x48,0x20210001,user32.dll-
- dllcall Sleep,1000,kernel32.dll-
- ::发送A 按键
- dllcall PostMessageA,%hPad%,0x100,0x41,0,user32.dll-
- dllcall Sleep,2000,kernel32.dll-
- dllcall PostMessageA,%hPad%,0x12,,,user32.dll-
- pause
复制代码
示例12: plink cmd命令提示符窗口隐藏运行- @echo off
- set cmdTitle=plink
- title %cmdTitle%
- for /f %%i in ('dllcall -r# FindWindowA##%cmdTitle%#user32.dll') do set hCmd=%%i
- dllcall ShowWindow,%hCmd%,,user32.dll-
- :: 443 远程ssh端口, 3390 本地socks端口
- plink -v -N ssh.com -l root -pw 123456 -P 443 -D 3390
复制代码