![Board logo](images/default/logo.gif)
标题: [其他] cmdex 超越capi 自定义可扩展cmd [打印本页]
作者: misaki 时间: 2017-6-1 15:23 标题: cmdex 超越capi 自定义可扩展cmd
cmdex,ex即extension。之所以说超越capi,是因为capi有很多缺陷:
- 作者按照自己的想法对cmd进行扩展,但没有提供额外的扩展空间。
- 语法晦涩难懂,难以使用,也背离了bat作为脚本的简洁性。
- 借助于set命令,只能作为二等公民。
- 兼容性差,注入的方式容易被误杀。
而cmdex虽然不直接提供扩展的命令,但提供了用于扩展的接口,使每个人都能定义自己的cmd。
特性:
- 提供像内置命令一样的调用方式,命令执行的优先级仅次于cmd内置命令和“cmdex”(预设命令),高于外部程序。
- 直接提供命令字和上一行命令(可能包含多条命令或不足一条命令)供处理,提供最大的自由度。
- >,<,>>等重定向一般不需要自行处理(未充分测试)。
扩展方式:
程序启动时加载所在目录的ext.dll,并调用其导出的ExtCallBack函数,参数含义可自行测试,例子如下:- #include <stdio.h>
- #include <stdlib.h>
- #include <windows.h>
-
- #define DLL_EXPORT __declspec(dllexport)
-
- #define HANDLED 0
- #define UNHANDLED 1
-
- #ifdef __cplusplus
- extern "C"
- {
- #endif
-
- int DLL_EXPORT ExtCallBack(const wchar_t * cmd, const wchar_t * cmdline);
-
- #ifdef __cplusplus
- }
- #endif
- wchar_t * mycmd = L"mycmd";
-
- int DLL_EXPORT ExtCallBack(const wchar_t * cmd, const wchar_t * cmdline)
- {
- if(wcsnicmp(cmd, mycmd, wcslen(mycmd)) == 0)
- {
- wprintf(L"cmd:%s\n", cmd);
- wprintf(L"lastcmdline:%s\n", cmdline);
- fflush(stdout);
- return HANDLED;//命令已处理
- }
- return UNHANDLED;//命令未处理,继续查找外部程序
- }
复制代码
用法随你喜欢,可以简单的添加命令,甚至可以做成一个插件管理器,把常用的第三方做成动态库供加载使用。
附件是程序本体和例子编译成的dll。
链接: https://pan.baidu.com/s/1RB4-lLK4z26I_NT3Wz9Kyg 提取码: schc
作者: bbaa 时间: 2017-6-3 13:16
capix欢迎你http://www.bathome.net/viewthrea ... amp;highlight=capix
作者: misaki 时间: 2017-6-4 00:50
回复 2# bbaa
capix只是避免了被误杀和改善了兼容性,其他方面并不比capi优越,当然也比不上这个。 而且定位不同,capix是在扩展cmd的功能,而这个是一个提供扩展的平台,让你们随意hack cmd
作者: 老刘1号 时间: 2017-6-4 07:42
本帖最后由 老刘1号 于 2017-6-4 07:50 编辑
回复 3# misaki
貌似很不错的样子
作者: bbaa 时间: 2017-6-4 11:54
回复 3# misaki
Capix貌似也能扩展cmd吧
作者: Byaidu 时间: 2017-6-12 20:09
很厉害的样子,但只能注入一个DLL,不方便以后扩展
作者: bailong360 时间: 2017-6-12 20:34
本帖最后由 bailong360 于 2017-6-13 16:37 编辑
很cool,而且效率很高!
能否请教一下原理?
再提一个建议:如楼上所说只能加载一个dll局限性很大,除非再把ext.dll做成一个加载器.然而这样不如让cmdex提供一个load命令,用来加载其他dll.这样不同开发者开发的dll就可以同时使用
------------------------
测试了一下 发现有一个bug- @echo off
- set a=%s%
- my%__%cmd %a%
- pause
复制代码
这样一段代码,执行后输出的是- cmd:mycmd
- lastcmdline:my%__%cmd %a%
-
- 请按任意键继续. . .
复制代码
%__%和%a%没有被扩展,不过"cmd:mycmd"倒是得到了正确结果 望改进
作者: misaki 时间: 2017-6-14 21:52
回复 6# Byaidu
我上面提到可以把扩展dll做成插件管理器,这样就可以无限制扩展了,比较懒所以没有自己做
作者: misaki 时间: 2017-6-14 22:00
回复 7# bailong360
cmdline就只是上一条命令而已,并不是扩展环境后的,因为bat的命令不是按行来算的,比如复合命令和转义换行,所以为了灵活性就直接暴露出来而不是我来处理
某种意义上这样可以写出不属于bat的语法,比如带括号的函数,等号赋值等.
实现的本质还是hook api,hook了wcsicmp和wcschr
ps:好久没在bat吧看见你了,我贴吧id是gzhmbk
作者: bailong360 时间: 2017-6-15 12:10
本帖最后由 bailong360 于 2017-6-15 12:18 编辑
回复 9# misaki
前段时间备战高考 就没怎么来了
输入cmdex其实就看到你的ID了/手动斜眼
其实想到了你可能是hook了字符串处理的函数...但是觉得以这些函数的使用频率对效率影响应该比较大,就排除了这种可能性......看来功力尚浅啊
不过这倒是给了我一个新思路
交给开发者来处理命令行感觉有利有弊吧
作者: misaki 时间: 2017-6-16 22:12
回复 10# bailong360
soga,因为bat效率实在太低了,所以这点hook影响不大![](images/smilies/default/lol.gif)
确实有利有弊,不过还是觉得从程序本体抽离出来更好,方便改动
作者: bailong360 时间: 2017-6-16 22:16
本帖最后由 bailong360 于 2017-6-16 22:21 编辑
回复 11# misaki
测试过各系统下的兼容性吗? 感觉这个很有戏
试着编写了一个AddCmd tcc编译通过
将变量扩展和参数都处理了一下,应该是个通常情况下比较友好的接口- #include <stdio.h>
- #include <windows.h>
- #include <shellapi.h>
-
- #define DLL_EXPORT __declspec(dllexport)
- #define HANDLED 0
- #define UNHANDLED 1
- #define MAX_CMD_LENGTH 512
-
- typedef struct cmdTable {
- wchar_t cmd[MAX_CMD_LENGTH];
- int (*func)(int, wchar_t *[]);
- struct cmdTable *next;
- } CMDTABLE;
-
- DLL_EXPORT int ExtCallBack(wchar_t *, wchar_t *);
- char* WcharToChar(wchar_t *wstr);
- int AddCmd(int argc, wchar_t *cmdline[]);
-
- CMDTABLE cmd_Load = {L"AddCmd", AddCmd, NULL};
- CMDTABLE *head = &cmd_Load;
- CMDTABLE *tail = &cmd_Load;
-
- DLL_EXPORT int ExtCallBack(wchar_t *cmd, wchar_t *cmdline)
- {
- CMDTABLE *current = head;
- do {
- if (!wcsnicmp(cmd, current->cmd, wcslen(current->cmd))) {
- int argc;
- wchar_t **argv;
- wchar_t newcmdline[MAX_CMD_LENGTH];
- ExpandEnvironmentStringsW(cmdline, newcmdline, MAX_CMD_LENGTH + 1);
- newcmdline[wcslen(newcmdline) - 2] = '\0'; //去除末尾的\n
- argv = CommandLineToArgvW(newcmdline, &argc);
- current->func(argc, argv);
- LocalFree(argv);
- return HANDLED;
- }
- current = current -> next;
- } while (current != NULL);
- return UNHANDLED;
- }
-
- char* WcharToChar(wchar_t *wstr)
- {
- int len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
- char *str = (char *)malloc(len * sizeof(char));
- WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);
- return str;
- }
-
- int AddCmd(int argc, wchar_t *argv[])
- {
- if (argc < 4) {
- puts("Usage: AddCmd YourCmd YourDll YourFunc");
- puts("**YourFunc should be defined like this \"int YourFunc(int argc, wchar_t *argv[])\"");
- return 0;
- }
- HMODULE hDLL = LoadLibraryW(argv[2]);
- char *funcName = WcharToChar(argv[3]);
- void *func = (void *)GetProcAddress(hDLL, funcName);
-
- if (hDLL == NULL) {
- fprintf(stderr, "ERROR:can't load dll \"%S\"", argv[2]);
- free(funcName);
- return 0;
- } else if (func == NULL) {
- fprintf(stderr, "ERROR:can't load func \"%s\"", funcName);
- free(funcName);
- return 0;
- }
- tail->next = (CMDTABLE *)malloc(sizeof(CMDTABLE));
- wcscpy(tail->next->cmd, argv[1]);
- tail->next->func = (void *)GetProcAddress(hDLL, funcName);
- tail->next->next = NULL;
- tail = tail->next;
- free(funcName);
- return 0;
- }
复制代码
作者: misaki 时间: 2017-6-17 19:51
回复 12# bailong360
试了xpsp3和8.1的,所以8.1之前应该没问题,win10没试过
作者: bailong360 时间: 2017-6-17 21:21
回复 13# misaki
刚刚又想到了一个问题
ExpanEnvironmentStringsW只能扩展以%%包裹的变量,!!好像不好处理- -
作者: misaki 时间: 2017-6-18 12:23
回复 14# bailong360
发帖的时候忘记说了,这个和cmd有点不同,如果自己处理命令行的话,%%也是变量延迟扩展的效果,实现可以参考nt4的源码吧
欢迎光临 批处理之家 (http://bathome.net./) |
Powered by Discuz! 7.2 |