2008년 09월 16일
Application Virtualization의 비밀
Application Virtualization이 하는일은 어플리케이션이 실행되는 가상환경을 만들어서
실제 운영체제에는 아무런 영향을 미치지 않게 만들어주는 것입니다.
가령 어플리케이션이 하드디스크에 파일을 저장하더라도, 레지스트리를 변경하더라도
실제 하드디스크나 레지스트리는 아무런 영향을 받지 않는 것이죠.
처음에 이러한 것을 구현하기 위해서는 레지스트리 필터나 파일시스템 필터 같은것들이
필요하다고 생각이 됬습니다. 실제로 SandBoxIE같은 경우가 그런식으로 구현이 된 것이고요.
여러 논문들중에도 이런 방법으로 구현된 것들이 있었습니다.
하지만 현재 시중에 나와있는 VMWare ThinApp같은경우에는 드라이버가 아무것도 설치되지
않고 유저모드에서 모든일을 처리하고 있었습니다.
어떻게 파일/레지스트리 가상화가 이루어질까 생각을하다가
어플리케이션이 사용하는 api들을 모두 가로채서 그안에서 무슨일을 꾸미는 것은
아닐까..라는 생각을 하게 되었죠!!.. 그래서 아래와 같은 실험을 해보았습니다.
아래는 제가 만든 VApp.exe프로그램이 CreateFileW를 호출했을 때 call stack을 보인 것입니다.
0:000> kvn
*** WARNING: Unable to verify checksum for VApp.exe
# ChildEBP RetAddr Args to Child
00 0012f364 004eacc9 00692820 80000000 00000001 kernel32!CreateFileW (FPO: [Non-Fpo])
01 0012f5a8 004f6e00 00000000 00000176 00000004 VApp!CVAppDlg::OnBnClickedButton2+0xf9
02 0012f5ec 004f753f 0012fe18 000003e9 00000000 VApp!_AfxDispatchCmdMsg+0xb0
03 0012f650 004fcd61 000003e9 00000000 00000000 VApp!CCmdTarget::OnCmdMsg+0x2df
04 0012f68c 00507f9d 000003e9 00000000 00000000 VApp!CDialog::OnCmdMsg+0x21
05 0012f6f0 00506f27 000003e9 000a0f88 7c9244e1 VApp!CWnd::OnCommand+0x16d
06 0012f828 00506e80 00000111 000003e9 000a0f88 VApp!CWnd::OnWndMsg+0x77
07 0012f848 0050439e 00000111 000003e9 000a0f88 VApp!CWnd::WindowProc+0x30
08 0012f8c4 00504894 0012fe18 000a0f92 00000111 VApp!AfxCallWndProc+0xee
09 0012f8e4 77cf8709 000a0f92 00000111 000003e9 VApp!AfxWndProc+0xa4
0a 0012f910 77cf87eb 004d8e79 000a0f92 00000111 USER32!InternalCallWinProc+0x28
0b 0012f978 77cfb743 00000000 004d8e79 000a0f92 USER32!UserCallWinProcCheckWow+0x150
0c 0012f9b4 77cfb7ab 009deb18 009dcce8 000003e9 USER32!SendMessageWorker+0x4a5
0d 0012f9d4 77186ff6 000a0f92 00000111 000003e9 USER32!SendMessageW+0x7f
0e 0012f9f4 771870d8 00177938 00000000 00040038 COMCTL32!Button_NotifyParent+0x3d
0f 0012fa10 771893dd 00177938 00000001 0012fb08 COMCTL32!Button_ReleaseCapture+0xd7
10 0012faa0 77cf8709 000a0f88 00000202 00000000 COMCTL32!Button_WndProc+0x887
11 0012facc 77cf87eb 77188b56 000a0f88 00000202 USER32!InternalCallWinProc+0x28
12 0012fb34 77cf89a5 00000000 77188b56 000a0f88 USER32!UserCallWinProcCheckWow+0x150
13 0012fb94 77cf89e8 00175a58 00000000 0012fbc8 USER32!DispatchMessageWorker+0x306
0:000> db 00692820
00692820 63 00 3a 00 5c 00 6d 00-79 00 66 00 69 00 6c 00 c.:.\.m.y.f.i.l.
00692830 65 00 2e 00 74 00 78 00-74 00 00 00 00 00 00 00 e...t.x.t.......
CreateFileW의 return 주소가 004eacc9 이고요... c:\myfile.txt를 open하는 것을 확인가능합니다.
0:000> u 004eacc9 -6
VApp!CVAppDlg::OnBnClickedButton2+0xf3 [d:\mydocuments\devguru\sample\vapp\vapp\vappdlg.cpp @ 235]:
004eacc3 call dword ptr[VApp!_imp__CreateFileW (00780928)]
004eacc9 cmp esi,esp
004eaccb call VApp!ILT+39135(__RTC_CheckEsp) (004dc8e4)
004eacd0 mov dword ptr [ebp-144h],eax
004eacd6 push 100h
004eacdb push 0
004eacdd lea eax,[ebp-120h]
004eace3 push eax
예.. import table에서 createfilew의 주소를 가져오네요...
0:000> dd 00780928 l1
00780928 7c810976
예..import table에 kernel32!createfilew주소가 담겨있는 것을 아래와 같이 확인 가능하네요
0:000> u 7c810976
kernel32!CreateFileW:
7c810976 mov edi,edi
7c810978 push ebp
7c810979 mov ebp,esp
7c81097b sub esp,58h
7c81097e mov eax,dword ptr [ebp+18h]
7c810981 dec eax
7c810982 je kernel32!CreateFileW+0x56 (7c81e6a4)
7c810988 dec eax
이번엔 가상화가 적용된 VApp.exe의 CreateFileW를 잡아봤았습니다.
1: kd> kvn
# ChildEBP RetAddr Args to Child
00 0012c75c 00d5a102 0012cbd8 80000000 00000001 kernel32!CreateFileW (FPO: [Non-Fpo])
WARNING: Frame IP not in any known module. Following frames may be wrong.
01 0012ce3c 77cfb3a7 00d7eefc 000a02a8 00000282 0xd5a102
02 0012e5e4 00d1cfd3 0012e838 80000000 00000001 USER32!DefWindowProcW+0x86 (FPO: [Non-Fpo])
03 0012ea54 004eacc9 7c810760 00692820 80000000 0xd1cfd3
04 0012ec9c 004f6e00 00000000 00000176 00000004 VApp!CVAppDlg::OnBnClickedButton2+0xf9
05 0012ece0 004f753f 0012f534 000003e9 00000000 VApp!_AfxDispatchCmdMsg+0xb0
06 0012ed44 004fcd61 000003e9 00000000 00000000 VApp!CCmdTarget::OnCmdMsg+0x2df
07 0012ed80 00507f9d 000003e9 00000000 00000000 VApp!CDialog::OnCmdMsg+0x21
08 0012ede4 00506f27 000003e9 000a02a8 6ed1b8d0 VApp!CWnd::OnCommand+0x16d
09 0012ef1c 00506e80 00000111 000003e9 000a02a8 VApp!CWnd::OnWndMsg+0x77
0a 0012ef3c 0050439e 00000111 000003e9 000a02a8 VApp!CWnd::WindowProc+0x30
0b 0012efb8 00504894 0012f534 00140178 00000111 VApp!AfxCallWndProc+0xee
0c 0012efd8 77cf8734 00140178 00000111 000003e9 VApp!AfxWndProc+0xa4
0d 0012f004 77cf8816 004d8e79 00140178 00000111 USER32!InternalCallWinProc+0x28
0e 0012f06c 77cfb89b 00000000 004d8e79 00140178 USER32!UserCallWinProcCheckWow+0x150
0f 0012f0a8 77cfb903 009ba900 009ccd18 000003e9 USER32!SendMessageWorker+0x4a5
10 0012f0c8 00d7ee0c 00140178 00000111 000003e9 USER32!SendMessageW+0x7f
11 0012f0ec 77187344 77cfb8ba 00140178 00000111 0xd7ee0c
12 0012f110 77187426 001724d0 00000000 00100032 comctl32!Button_NotifyParent+0x3d
13 0012f12c 7718972b 001724d0 00000001 0012f224 comctl32!Button_ReleaseCapture+0xd7
1: kd> db 0012cbd8
0012cbd8 43 00 3a 00 5c 00 44 00-6f 00 63 00 75 00 6d 00 C.:.\.D.o.c.u.m.
0012cbe8 65 00 6e 00 74 00 73 00-20 00 61 00 6e 00 64 00 e.n.t.s. .a.n.d.
0012cbf8 20 00 53 00 65 00 74 00-74 00 69 00 6e 00 67 00 .S.e.t.t.i.n.g.
0012cc08 73 00 5c 00 41 00 64 00-6d 00 69 00 6e 00 69 00 s.\.A.d.m.i.n.i.
0012cc18 73 00 74 00 72 00 61 00-74 00 6f 00 72 00 5c 00 s.t.r.a.t.o.r.\.
0012cc28 14 bc d5 d0 20 00 54 d6-74 ba 5c 00 56 00 41 00 .... .T.t.\.V.A.
0012cc38 70 00 70 00 2e 00 65 00-78 00 65 00 00 00 00 00 p.p...e.x.e.....
0012cc48 28 02 00 00 00 00 00 00-00 00 00 00 00 00 00 00 (...............
네.. 아까와는 달리 C:\Documents and Settings\Administrator\바탕화면\VApp.exe를 open하고 있네요..
중간에 누군가 파일접근을 가상화하고 있다는 것을 알 수 있습니다.
VApp!CVAppDlg::OnBnClickedButton2+0xf3:
001b:004eacc3 ff1528097800 call dword ptr [VApp!_imp__CreateFileW (00780928)]
예 이번에도 마찬가지로.. import table에서 createfilew의 주소를 가져와서 호출하고 있네요..
1: kd> dd 00780928 l1
00780928 7c800360
예..이번에는..아까와는 달리 jmp코드가 삽입되어 있습니다.
1: kd> u 7c800360
kernel32!_imp___wcsnicmp <PERF> (kernel32+0x360):
7c800360 e9b9fc7803 jmp 7ff9001e
1: kd> u 7ff9001e
7ff9001e 686007817c push offset kernel32!CreateFileW (7c810760)
7ff90023 6850cfd100 push 0D1CF50h
7ff90028 e9c376de80 jmp 00d776f0
지금까지 디버깅한 결과를 미루어보아 import table을 모두 후킹을 하고 이 안에서
레지스트리나 파일접근이 일어 날때 가상화를 위한 적절한 수행을 하고
원본 함수를 호출하고 있는 것을 알수가 있었습니다...
실제로 이러한 제품을 만들고자 한다면,
좀더 방대한 작업이 필요할 것 같다는 생각이 듭니다.
레지스트리 관련 함수
파일접근 관련 함수
COM/ActiveX 관련 함수
등.. 처리해줘야할 함수들이 상당히 많을 것 같다는 생각이 드네요..^^
....이미 알고나니..그리 대단할 것 없는 기술일지도 모르지만
처음에 이러한 아이디어를 생각해낸 사람은 정말 대단하네요..^^...
무엇이든 제일먼저 시작한다는 것!
정말 어려운 일인 것 같습니다.
# by | 2008/09/16 16:42 | WORK | 트랙백 | 덧글(0)






☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]