原文链接:https://www.f2er.com/react/308179.htmlRunDll32.exe是微软系统自带的一个小程序,功能是加载系统中的dll,并且作为程序运行。控制面板里面有很多选项都可以由Rundll.exe进行加载运行。现在,我们根据reactos当中的源代码对其实现进行分析。 首先看rundll32.exe调用进行调用的函数原型(源文件当中对函数的UNICODE和ASCII进行了区分)。typedef int (WINAPI *DllWinMainW)( HWND hWnd,HINSTANCE hInstance,LPWSTR lpwCmdLine,int nCmdShow );整个函数当中的最主要部分是CommandLineToArgv,通过函数名称可以知道这个函数就是对输入的命令行进行分析,并且分解成为相应的参数。
下面对其进行分步分析(完整的代码在我的CSDN资源里面)
第一步很简单,就是验证函数参数的有效性。
第二步,计算命令行当中参数的个数。因为有一个参数可能会被当做参数对DllWinMainW进行调用。所以参数数目可能是三个可能是四个。
// 计算参数的数目 while (nNames < 4) { if (*lpSrc == 0 || (*lpSrc == _T(',') && nNames == 2) || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) { // 不在引号当中的空格表示新一行的开始,通过CMD命令行的DIR命令可以看到C盘下面的program file实际上市带引号的。 argc++;//此处由0开始递增,正好去掉第一个参数也就是rundll.exe // 跳过参数当中的空格 while (*lpSrc == _T(' ') || *lpSrc == _T('\t') || (*lpSrc == _T(',') && nNames == 2)) lpSrc++; if (*lpSrc == 0) break; if (nNames >= 3) { // 为最后一个参数进行递增 argc++; break; } nBSlash = 0;//讲斜划线的计数清零,并且设置第一个字符标志为真 bFirstChar = TRUE; continue; } else if (*lpSrc == _T('\\')) { // 递增连续的斜划线的计数 nBSlash++; bFirstChar = FALSE; } else if (*lpSrc == _T('\"') && !(nBSlash & 1)) {//在斜划线为奇数的时候,那么表示对引号的转义字符 // 只要遇到引号则在引号当中的状态需要发生改变 bInQuotes = !bInQuotes;//引号实际不会改变第一个字符的状态 nBSlash = 0;//因为引号状态改变之后,表明一类新的字符串开始,所以斜划线计数要清零 } else { // 其他的字符 nBSlash = 0; if (bFirstChar && ((*lpSrc != _T('/') && nNames <= 1) || nNames > 1))//这的的‘/’字符表示跟在rundll.exe后面的子命令 nNames++; bFirstChar = FALSE; } lpSrc++; }第三步,分配内存,并且将参数按照顺序写到二位数组当中。
lpDest = lpArg = (LPTSTR)(argv + argc);//注意这里由于argv是二维数组,那么头部保存到各个一位数组的地址,这样可以节省内存
// 填充参数队列
while (nNames < 4) {
if (*lpSrc == 0 || (*lpSrc == _T(',') && nNames == 2) ||((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) {
// 不在引号当中的空格代表新一行的开始
// 参数的终结符
*lpDest++ = 0;//表明lpDest当中为一个参数序列
argv[argc++] = lpArg;//这里lparg实际上指向lpdest的头部,所以刚好放到argv当中去
// 跳过参数当中的空格
while (*lpSrc == _T(' ') || *lpSrc ==_T('\t') || (*lpSrc == _T(',') && nNames == 2))
lpSrc++;
if (*lpSrc == 0)
break;
lpArg = lpDest;//重新使得lpdest的头部等于lparg
if (nNames >= 3) {
// 首先将lparg当中的值赋给argv
argv[argc++] = lpArg;
_tcscpy(lpArg,lpSrc);因为是指针赋值,所以这里同样也是拷贝到argv[argc]
break;
}
nBSlash = 0;
bFirstChar = TRUE;
continue;
}
else if (*lpSrc == _T('\\')) {
*lpDest++ = _T('\\');
lpSrc++;
// 递增连续的斜划线
nBSlash++;
bFirstChar = FALSE;
}
else if (*lpSrc == _T('\"')) {
if (!(nBSlash & 1)) {
// 如果引号前面出现偶数个斜划线
// 那么引号将不会被输出
lpDest -= nBSlash / 2;
bInQuotes = !bInQuotes;
}
else {
// 如果奇数个斜划线出现在引号前面
// 将输出一个引号
lpDest -= (nBSlash + 1) / 2;
*lpDest++ = _T('\"');
bFirstChar = FALSE;
}
lpSrc++;
nBSlash = 0;
}
else {
// 拷贝其他的字符
if (bFirstChar && ((*lpSrc!= _T('/')&& nNames <= 1) || nNames > 1))
nNames++;
*lpDest++ = *lpSrc++;
nBSlash = 0;
bFirstChar = FALSE;
}
}