【文章标题】: 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
- 标 题:DIY 让我们的任务管理器再智能一点
- 作 者:我是土匪
- 时 间:2010-02-07 13:33:39
- 链 接:http://bbs.pediy.com/showthread.php?t=106870