【文章标题】: DIY 让我们的任务管理器再智能一点
【文章作者】: 我是土匪
【作者邮箱】: lwzy-crack@163.com
【作者主页】: http://lwzy-crack.blog.163.com
【软件名称】: Windows 任务管理器
【下载地址】: 自己搜索下载
【保护方式】: 无
【使用工具】: OD,ResHacker,AddZero,C32Asm
【操作平台】: Windows Xp Sp3
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  近日工作中总是需要把同一个进程,启动N个。然后在一个一个结束。(无聊……… ^_^),于是乎,萌生了一个想法,写一个
  程序,批量结束进程,这样不就可以了,呵呵!然后我就写了一个exe程序来干这事。
  
  又到周末了,无聊中,想逛街,兜里没有钱;想和老婆一起聊聊天,可是我还没有女朋友;上VS玩 DOTA,老是遇见外挂,开始
  不到3秒就爆基地,爆就爆吧,我认了。谁叫我倒霉呢!最气人的是,我们“杀”的正爽的时候,只见屏幕上,我的队员在读秒,
  45s过去了,我的队友掉线了一个人,这时,又有一个队友在读秒,看来是遇见踢人挂了。把我的队友都踢掉了。剩下我一个,
  我问他为啥不踢我呢?“把你踢了,就不给分了。”,一个**回答说。
  
  哎!没辙了。不玩了,学会习吧,我学习绝对是被逼的。
  
  学啥呢?面对浩瀚的知识海洋,我又茫然了。看了一会野外生存的电子书,看的我只“反胃”,别问我为啥?你看一会就知道了。
  
  牛顿发现万有引力,是因为看见苹果掉到地上了。我为啥要Diy任务管理器,这得问上帝,我自己也说不清楚。
  
  
  书归正传,开始干活
  在我有这个想法的时候,我先思考这个思路的可行性,然后在动手,这是一个很好的习惯(呵呵,别扔我鸡蛋哦!)。这就好比
  盖楼房,你要是没有楼房的图纸,盖了几层楼后就会不知道该怎么盖了。
  
  本次实现的思路借鉴了 slore 的《第一次PEDIY---让Windows 任务管理器更强,更人性!》文章中的思路,如果要是批量结束同一
  个进程,就要想办法获得每个进程的控制权限(OpenProcess),这样才能控制这个进程,可想而知,要是用汇编些代码,要写好
  多行,我汇编功底薄的就像女人穿的透明的黑乳罩一样,Very 迷人(别扔砖头,我不是色狼)。被逼无奈,我就写了一个 
  (KillProcess.dll)文件。Dll文件应该导出两个函数
  (1)GetFileNamebyPath
  功能:根据路径名,返回程序名,例如:SS:(UNICODE ""C:\WINDOWS\notepad.exe" C:\Documents and Settings\Owner\")
  返回的应该是“notepad.exe”。
  (2)BKillProcess
  功能:根据程序名(例如:“notepad.exe”),遍历进程,遇到同名的,就杀进程。
  函数执行成功,返回真,否则返回假。
  
  呵呵,如果不嫌代码长,可以写在一个函数里面,视个人习惯而定,在调用的时候,我们调用第一个函数,在第一个函数末尾
  调用第二个函数,这样能使我少写一些汇编指令。(如果有兴趣,你可以自己试试,就能体验其中的奥妙了。)
  
  用C32Asm打开任务管理器,
  00015F60>01016B60    写入“KillProcess.dll”
  00015F70>01016B70    写入“GetFileNamebyPath”
  00015F90>01016B90    写入“BKillProcess”
  
  编辑好后,保存。
  
  
                     传入文件路径              干完活以后
          动态加载dll>干活(杀进程)>卸载dll(卸磨杀驴)
  
                                     ^
                                     |
                                     |         
                                     |因为传入的文件路径是Unicode的字符串,里面包含 " "
                                     |所以编写dll的时候要注意。如果不转换也可以,就用Unicode进行比较吧
                                     |
                                     |
                       
           
  Dll 怎么写,我就不说了,应该很容易,下面我说一下如何获得文件路径,以及加载dll程序。
  首先添加右键菜单,用Reshacker载入程序,选择“Menu”>“111”>“2052”
  
  
  111 MENU
  LANGUAGE LANG_CHINESE, 0x2
  {
  POPUP "Banana"
  {
    MENUITEM "打开所在目录(&O)",  50127
    MENUITEM "结束所有同名进程(&K)",  50130
    MENUITEM SEPARATOR
    MENUITEM "结束进程(&E)",  40028
    MENUITEM "结束进程树(&T)",  40105
    MENUITEM "调试(&D)",  40027
    MENUITEM "创建转储文件(&C)",  40131
    MENUITEM SEPARATOR
    POPUP "设置优先级(&P)"
    {
      MENUITEM "实时(&R)",  40029
      MENUITEM "高(&H)",  40031
      MENUITEM "高于标准(&A)",  40030
      MENUITEM "标准(&N)",  40032
      MENUITEM "低于标准(&B)",  40033
      MENUITEM "低(&L)",  40034
      MENUITEM "关系设置(&A)...",  40055
    }
    MENUITEM "关系设置(&A)...",  40055
  }
  }
  
  
  添加后,保存就可以了。
  注意事项:添加的资源“ID”不能相同,我这里定义的资源ID的值是 “50130”,转化为16进制就是“C3D2”
  
  好了,资源我们已经添加上了,运行一下我们刚刚修改的任务管理器,可以运行,没问题,把属性页切换到“进程”
  单击鼠标右键,发现我们刚刚添加的菜单了。如下图所示:
  
  
  
  
  
  
  
  我们再来添加消息响应代码。先用zeroadd,添加一个区段,名称随便填写,写什么都行,大小为大于300(这个大小是字节,
  我们填写的原则是:宁大勿小),根据“slore”的文章,我们非常容易的找到了消息处理代码。如下所示:
  
  0100BE23  |> \81F9 5D9C0000 CMP ECX,9C5D
  0100BE29  |.  7C 6A         JL SHORT taskmgr.0100BE95
  0100BE2B  |.  81F9 629C0000 CMP ECX,9C62
  0100BE31  |.  7E 55         JLE SHORT taskmgr.0100BE88
  0100BE33  |.  81F9 779C0000 CMP ECX,9C77
  0100BE39  |.  74 3D         JE SHORT taskmgr.0100BE78
  0100BE3B  |.  81F9 A99C0000 CMP ECX,9CA9
  0100BE41  |.  74 25         JE SHORT taskmgr.0100BE68
  0100BE43  |.  81F9 C39C0000 CMP ECX,9CC3
  0100BE49  |.  74 15         JE SHORT taskmgr.0100BE60
  0100BE4B  |.  81F9 CFC30000 CMP ECX,0C3CF
  0100BE51  |.  75 42         JNZ SHORT taskmgr.0100BE95
  0100BE53  |.  85C0          TEST EAX,EAX
  0100BE55  |.  74 3E         JE SHORT taskmgr.0100BE95
  0100BE57  |.  8BC8          MOV ECX,EAX
  0100BE59  |.  E8 F8E8FFFF   CALL taskmgr.0100A756
  
  修改为:
  0100BE23   > \81F9 5D9C0000 CMP ECX,9C5D
  0100BE29   .  7C 6A         JL SHORT DIY任务?0100BE95
  0100BE2B   .  81F9 629C0000 CMP ECX,9C62
  0100BE31   .  7E 55         JLE SHORT DIY任务?0100BE88
  0100BE33   .  81F9 779C0000 CMP ECX,9C77
  0100BE39   .  74 3D         JE SHORT DIY任务?0100BE78
  0100BE3B   .  81F9 A99C0000 CMP ECX,9CA9
  0100BE41   .  74 25         JE SHORT DIY任务?0100BE68
  0100BE43   .  81F9 C39C0000 CMP ECX,9CC3
  0100BE49   .  74 15         JE SHORT DIY任务?0100BE60
  0100BE4B   .- E9 B0F10400   JMP DIY任务?0105B000              ;跳到零区,这里我添加一个新的区段,在里面写补丁代码
  0100BE50   .  75 43         JNZ SHORT DIY任务?0100BE95
  0100BE52   .  90            NOP
  0100BE53   .  85C0          TEST EAX,EAX
  0100BE55   .  74 3E         JE SHORT DIY任务?0100BE95
  0100BE57   .  8BC8          MOV ECX,EAX
  0100BE59   .  E8 F8E8FFFF   CALL DIY任务?0100A756
  
  
  
  
  
  
  
  
  来到0105B000这里:
  
  0105B000    81F9 D2C30000   CMP ECX,0C3D2                      ;判断是不是“结束所有同名进程”的消息
  0105B006    74 1F           JE SHORT DIY任务?0105B027          ;是则跳到地址“0105B027 ”执行消息响应代码。
  0105B008    81F9 CFC30000   CMP ECX,0C3CF                      ;这是是我们刚才打补丁地址的原代码,我们给还原
  0105B00E  - E9 3D0EFBFF     JMP DIY任务?0100BE50               ;还原后,跳转到原地址继续执行
  0105B013    0000            ADD BYTE PTR DS:[EAX],AL
  0105B015    0000            ADD BYTE PTR DS:[EAX],AL
  0105B017    0000            ADD BYTE PTR DS:[EAX],AL
  
  
  
  
  
  
  来到0105B000这里:
  
  0105B027    60              PUSHAD                             ;保护环境,人人有责!
  0105B028    8B40 08         MOV EAX,DWORD PTR DS:[EAX+8]       ;把进程“PID”赋值给EAX
  0105B02B    50              PUSH EAX                           ;把“PID”压栈
  0105B02C    68 606B0101     PUSH DIY任务?01016B60              ; ASCII "KillProcess.dll"
  0105B031    FF15 D0100001   CALL DWORD PTR DS:[<&kernel32.LoadLibrar>; kernel32.LoadLibraryA
  0105B037    8BF0            MOV ESI,EAX                        ;把EAX中的HMODULE保存到ESI里面
  0105B039    85F6            TEST ESI,ESI                       ;判断ESI是否为0
  0105B03B    75 06           JNZ SHORT DIY任务?0105B043         ;不为0就跳到0105B043继续执行
  0105B03D    61              POPAD                              ;如果为0,就说明Loadlibrary失败,恢复环境,
  0105B03E  - E9 520EFBFF     JMP DIY任务?0100BE95               ;恢复环境后,跳到默认消息处理流程,继续执行
  0105B043    8B3D 54110001   MOV EDI,DWORD PTR DS:[<&kernel32.GetProc> ;把GetProcAddress的地址保存到EDI里面
  0105B049    68 706B0101     PUSH DIY任务?01016B70              ;ASCII "GetFileNamebyPath"
  0105B04E    56              PUSH ESI                           ;把HMODULE参数压栈
  0105B04F    FFD7            CALL EDI                     ;调用GetProcAddress函数,获得GetFileNamebyPath函数的地址
  0105B051    8BD8            MOV EBX,EAX                        ;把GetFileNamebyPat函数的地址保存到EBX
  0105B053    85DB            TEST EBX,EBX                       ;判断EBX是否为0
  0105B055    75 06           JNZ SHORT DIY任务?0105B05D         ;不为0就跳到0105B05D继续执行
  0105B057    61              POPAD                        ;如果为0,就说明调用GetProcAddress函数失败,恢复环境,
  0105B058  - E9 380EFBFF     JMP DIY任务?0100BE95               ;恢复环境后,跳到默认消息处理流程,继续执行
  0105B05D    68 906B0101     PUSH DIY任务?01016B90              ;ASCII "BKillProcess"
  0105B062    56              PUSH ESI                           ;把HMODULE参数压栈
  0105B063    FFD7            CALL EDI                     ;调用GetProcAddress函数,获得BKillProcess函数的地址
  0105B065    8BF8            MOV EDI,EAX                        ;把BKillProcess函数的地址保存到EDI
  0105B067    85FF            TEST EDI,EDI                       ;判断EDI是否为0
  0105B069    75 06           JNZ SHORT DIY任务?0105B071         ;不为0就跳到0105B071继续执行
  0105B06B    61              POPAD                        ;如果为0,就说明获得BKillProcess函数的地址,恢复环境,
  0105B06C  - E9 240EFBFF     JMP DIY任务?0100BE95               ;恢复环境后,跳到默认消息处理流程,继续执行
  0105B071    58              POP EAX                            ;把“PID”弹出栈
  0105B072    60              PUSHAD                             ;保存当前的环境
  0105B073    90              NOP
  0105B074    90              NOP
  0105B075    83F8 04         CMP EAX,4                          ;判断是不是SYSTEM.EXE进程
  0105B078   /0F84 81000000   JE DIY任务?0105B0FF                ;是则转恢复现场
  0105B07E    50              PUSH EAX                           ;ProcessId进栈
  0105B07F    6A 00           PUSH 0                             ;|Inheritable = FALSE
  0105B081    68 10040000     PUSH 410                           ; |Access = VM_READ|QUERY_INFORMATION
  0105B086    FF15 14110001   CALL DWORD PTR DS:[<&kernel32.OpenProces>; kernel32.OpenProcess
  0105B08C    8985 00FAFFFF   MOV DWORD PTR SS:[EBP-600],EAX     ;将OpenProcess打开的句柄保存
  0105B092    83A5 F8F9FFFF 0>AND DWORD PTR SS:[EBP-608],0       ;将字符串保存地址清零
  0105B099    85C0            TEST EAX,EAX                       ;判断EAX是否为0即OpenProcess是否成功
  0105B09B    74 62           JE SHORT DIY任务?0105B0FF          ;不成功跳到恢复现场
  0105B09D    68 04010000     PUSH 104
  0105B0A2    8D85 F4FBFFFF   LEA EAX,DWORD PTR SS:[EBP-40C]    
  0105B0A8    50              PUSH EAX                           ;传入保存结果地址
  0105B0A9    FFB5 00FAFFFF   PUSH DWORD PTR SS:[EBP-600]        ;OpenProcess句柄
  0105B0AF    E8 9475FBFF     CALL DIY任务?01012648              ;获取进程映像路径的函数
  0105B0B4    85C0            TEST EAX,EAX                       ;EAX保存查询到的字符串WORD数
  0105B0B6    74 31           JE SHORT DIY任务?0105B0E9          ;没有查询到则转CloseHandle
  0105B0B8    8D3C00          LEA EDI,DWORD PTR DS:[EAX+EAX]     ;转为字节数保存到EDI
  0105B0BB    8D47 02         LEA EAX,DWORD PTR DS:[EDI+2]       ;字符串结尾0000需要两个字节
  0105B0BE    50              PUSH EAX                           ; /Size
  0105B0BF    6A 40           PUSH 40                            ; |Flags = LPTR
  0105B0C1    FF15 38110001   CALL DWORD PTR DS:[<&kernel32.LocalAlloc>; kernel32.LocalAlloc
  0105B0C7    85C0            TEST EAX,EAX                       ;判断是否申请成功
  0105B0C9    8985 F8F9FFFF   MOV DWORD PTR SS:[EBP-608],EAX     ;将申请到的空间首地址保存
  0105B0CF    74 18           JE SHORT DIY任务?0105B0E9          ;不成功则执行CloseHandle
  0105B0D1    8BCF            MOV ECX,EDI                        ;字节数存放到ECX
  0105B0D3    8BF8            MOV EDI,EAX                        ;字符串复制目的地址放入EDI
  0105B0D5    8BC1            MOV EAX,ECX                        ;复制字节数保存在EAX
  0105B0D7    C1E9 02         SHR ECX,2                          ;字节数/4=按DWORD复制的次数
  0105B0DA    8DB5 F4FBFFFF   LEA ESI,DWORD PTR SS:[EBP-40C]     ;字符串复制源地址存入ESI
  0105B0E0    F3:A5           REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] ;执行字符串双字复制
  0105B0E2    8BC8            MOV ECX,EAX                        ;复制字节数保存在ECX
  0105B0E4    83E1 03         AND ECX,3                          ;计算剩余字节数,即按字节复制次数
  0105B0E7    F3:A4           REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]  ;执行字符串字节复制
  0105B0E9    FFB5 00FAFFFF   PUSH DWORD PTR SS:[EBP-600]               ;OpenProcess句柄
  0105B0EF    FF15 5C110001   CALL DWORD PTR DS:[<&kernel32.CloseHandl> ;CloseHandle
  0105B0F5    8B85 F8F9FFFF   MOV EAX,DWORD PTR SS:[EBP-608]     ;读取保存的字符串地址
  0105B0FB    85C0            TEST EAX,EAX                       ;判断关闭句柄是否成功
  0105B0FD    75 07           JNZ SHORT DIY任务?0105B106         ;成功关闭句柄就跳到0105B106继续执行
  0105B0FF    61              POPAD                              ;否则就恢复环境
  0105B100    61              POPAD                              ;恢复环境,因为pushad两次
  0105B101  - E9 8F0DFBFF     JMP DIY任务?0100BE95               ;跳到默认的消息处理流程
  0105B106    61              POPAD                              ;恢复环境
  0105B107    8B85 F8F9FFFF   MOV EAX,DWORD PTR SS:[EBP-608]     ;把进程的映像路径保存到EAX
  0105B10D    50              PUSH EAX                           ;把映像路径压栈
  0105B10E    FFD3            CALL EBX                           ;调用“GetFileNamebyPath”函数
  0105B110    56              PUSH ESI                           ;把HMODULE参数压栈
  0105B111    FF15 D8100001   CALL DWORD PTR DS:[<&kernel32.FreeLibrar>; kernel32.FreeLibrary
  0105B117    61              POPAD                              ;恢复环境
  0105B118  - E9 780DFBFF     JMP DIY任务?0100BE95               ;跳转到默认的消息处理流程
  
  
  
  
  至此,所有的补丁代码完毕,保存后,任务管理器就可以运行了。(这里我只调用了“GetFileNamebyPath”函数,因为我
  把"BKillProcess"这个函数在“GetFileNamebyPath”末尾调用了,前面已经说了。也许你会问我又获得了"BKillProcess"地址
  做什么,呵呵,因为我刚开始的思路是分别调用每个函数,所有就获得了"BKillProcess"函数的地址,后来在实际操作中,我
  发现分两次调用,我就会破坏堆栈,在地址“0105B118”执行完后,来到下面的地址开始执行,执行完 “0100BE97”,程序就
  不知道该到哪里执行了。EIP被破坏了。所有我调用一次函数。如果谁知道这个原因,请帮我解释一下,谢谢!)
  
  0100BE95   > \5E            POP ESI                                  ;  分支 0100BDAA 默认案例
  0100BE96   .  5D            POP EBP
  0100BE97   .  C2 0800       RETN 8
  
  
  
  
  
  
  我又郁闷了,写了好久,刚要发布,突然发现我的QQ变成灰色的了,我断网了。无奈之下只好睡觉了。明天早晨在发布吧,
  谨以此文纪念我不幸的一天!
  
  
  说句题外话,马上要过年了。大家都注意安全,男同胞们少喝点酒,喝酒千万别开车,被抓到酒后驾车的抓,一次扣12分。
  女同胞们别自己走夜路。什么?你是单身,好办,你找我吧,免费的“护花使者”,呵呵^_^!
  
  最后祝大家在新的一年里面能有新的气色,政府官员:步步高升,生意人:财源滚滚,学生:学业有成,老人:福如东海,
  男人:彩旗飘飘,女人:找一个外面没有彩旗的好老公。祝所有人:笑口常开,心想事成,身体健康,万事如意。
  最后祝我自己明年能领个媳妇回家过大年!工资争取翻一番,能翻2翻更好,呵呵,多多益善!
  
--------------------------------------------------------------------------------
【经验总结】
  耐心,对一些重复性高,比较细致的工作,必须要有耐心。
  头脑,要学以致用,把日常生活和学习联系起来。多动脑,多动手。
  注意字符编码。微软里面的东西都是 Unicode 的,这么说不知道准确不准确,好处是支持65535个字符,支持各种符号的显示。
  
--------------------------------------------------------------------------------
【版权声明】: 转载请注明作者并保持文章的完整,文章出自看雪论坛。 谢谢!

                                                       2010年02月07日 01:21:57

本代码的着色效果由xTiNt自动完成
下载xTiNt


附件下载:

DIY 让我们的任务管理器再智能一点.rar