Reactos当中的Rundll的实现

RunDll32.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;

       }

    } 

 本文源代码地址:DUNDLL源代码



   

你可能感兴趣的:(Reactos当中的Rundll的实现)