안녕하세요. ReverseCore 입니다. 

책 원고 작성을 완료하였습니다.

모든 컨텐츠 작성을 마치고 자체 퇴고(8회)를 완료하였습니다.

이제 출판사에 넘겨줄 수 있겠네요. ^^~



<퇴고 작업을 도와준 아이패드>


분량


8섹션, 61챕터, A4 기준 1000 페이지 입니다.
885 개의 이미지와 65 개의 소스파일이 담겨있습니다.
책 이름도 결정 하였습니다. (나중에 공개할 께요~ ^^)


내용


기존 블로그의 내용 60% + 새로운 컨텐츠 40% 로 구성하였습니다.

블로그에 있는 내용들은 Windows XP + Visual C++ 6.0/2008 환경에서 작업했었습니다. 이를 최신 Windows 7 32bit + Visual C++ 2010 환경으로 재작업을 하였구요. 컨텐츠들의 순서 조정에 많은 고민을 하였습니다.

새로 추가된 내용들은 아래와 같습니다.


64 bit Computing / Debugging
고급 리버싱 (TLS, TEB, PEB, SEH, IA-32 Instruction 해석)
Anti-Debugging (Static, Dynamic, Advanced)
디버깅 실습 (Service, Self-Creation, PEImageSwitching, DebugBlocker)
 



일정


2010년 5월 1일 책을 쓰기로 마음 먹고 2011년 12월 3일 원고를 마감하였네요. 원고 작업만 19 개월 소요되었군요. (블로그 시작한날인 2009년 2월부터 따져보면 벌써 약 33 개월이 지났네요.)

아직까지는 제 인생 최대의 프로젝트라고 말할 수 있겠습니다. ^^

2011년 6월말쯤 8장 마지막 챕터를 끝내고 책에 뭐 빼먹은게 없나 살펴보니, 문득 제가 애초에 기획했던 모든 컨텐츠 작성을 끝냈다는 사실을 깨달았습니다.

약간 멍~ 했죠. 조금 재충전을 하고 퇴고 작업에 들어갔습니다. 노트북으로 들고 다니며 보는데 한계가 있어서 문서를 출력해서 보다가 분량이 너무 많아서 힘들었습니다. 그래서 아이패드에 문서를 전부 입력하고 PDF Viewer 앱과 터치펜으로 퇴고 작업을 했습니다. (퍼포먼스가 확 향상되더군요.) 약 5 개월간의 기나긴 퇴고 작업 끝에 드디어 원고를 탈고 할 수 있었습니다.

마침 아내가 아기와 외출한 시간(12월 3일 토요일 오후 6시)에 제가 계획한 8 단계 퇴고작업의 마지막 작업을 끝마칠 수 있었네요. 


소감


일단 기분이 몹시 좋습니다. 몸과 마음이 날아갈듯 하네요. ^^ 
마치 오랜 여행을 마치고 집에 돌아온 느낌이 드네요. 기쁜 마음에 이렇게 블로그에 글을 올려 봅니다. 


# 작업 속도

책을 쓸 때는 생각보다 작업 속도가 너무 느려서 도대체 언제쯤 책이 완성될 수 있을까 싶었습니다. 하루에 그림 하나 또는 캡쳐 두개 정도 밖에 못 할 때도 많았거든요. 하지만 그런 날들이 하루 이틀 쌓이니까 어느 순간부터는 "내가 언제 이렇게 많은 일을 했지?" 라는 생각이 들면서 목표 지점이 희미하게나마 보이기 시작했습니다. 


# 재작업

책을 쓰면서 가장 힘들었던 순간은 이미 한번 쓴 글을 두번 세번 다시 쓸 때 였습니다. 독자분들께 최신의 리버싱 경험을 드리기 위해 개발도구를 Visual C++ 2010 으로 바꾸고 작업환경을 Windows 7 으로 바꾸었습니다. 그러다보니 기존 문서를 그에 맞게 다시 캡쳐하고 변경된 주소를 찾아 고치는 작업들이 많았습니다. 지금와서 뒤돌아보니 그런 작업들이 가장 기억에 많이 남습니다. 


# 슬럼프

10 여회의 크고 작은 슬럼프를 경험하였습니다. 수많은 재작업과 검증, 생각대로 나오지 않는 글쓰기, 예상보다 훨씬 오래 걸리는 시간, 개인적인 외부 요인 등으로 인해서 글을 쓰지도 못하고 글쓰기 자체가 싫어지는 상황이 몇 번 닥쳤었죠. 스트레스가 쌓인 겁니다.

제가 새벽에 일어나 글을 쓰는 책상이 있는데요, 어느 순간에는 그쪽을 쳐다보기도 싫어지더군요. 그리고 저녁에는 퇴근 후 글을 쓰러 찾아가는 도서관이 있습니다. 한때는 그쪽으로 발길이 도저히 떨어지지 않는 날도 많았습니다.

다행인것은 그때마다 제 자신이 슬럼프 상황인걸 인식하고 극복하려고 노력했다는 것입니다.


# 응원

가끔 블로그에 방문해서 댓글에 답변도 달아드리고 제 책을 응원하는 글을 보면서 힘을 얻곤 했습니다. 그리고 부모님, 아내, 친구들, 회사 동료들까지 많은 분들께서 관심을 가져주시고 격려를 해주셨습니다.

이 자리를 빌어서 모든 분들께 감사 드립니다.

그리고 제가 좋아하는 독서도 많이 하고 사람들과 많이 어울려 다니면서 다시 용기를 얻어서 작업을 이어나갈 수 있었습니다. 그러다 결국 여기까지 올 수 있었구요.

"포기하기 전까지 실패란 없다. 시행착오가 있을 뿐이다. 시행착오를 거듭하다보면 언젠가 결국 성공하게 된다."

위 명언을 계속 새기면서 포기하지 않고 꾸준히 작업했더니 결국 원고가 완성되었습니다.


# 앞으로...

출판사와의 일정이 잡히면 블로그에 다시 공지해 드리겠습니다.

원고 작업을 한번 성공하니 자신감이 충만해 지는게 느껴집니다. 이번에 많은 경험과 시행착오를 겪어보니 두 번째 책도 금방 쓸 수 있을 것 같은 기분입니다. (2 탄을 기획 중인데요. 구체적으로 정리되면 알려드릴께요~)


다시 한번 모든 분들께 감사 드립니다. ^^~


ReverseCore

Trackback Address :: http://www.reversecore.com/trackback/95 관련글 쓰기

  1. Sun2Day 2011/12/05 02:58 댓글주소 | 수정 | 삭제 | 댓글

    우와....
    수고 하셨습니다!!
    정말 기대 되는 책입니다. +_+
    나오면 바로 머스트해브 아이템으로 등록하겠습니다 +_+

  2. ph4nt0m 2011/12/05 03:06 댓글주소 | 수정 | 삭제 | 댓글

    Reversecore님의 블로그 글을 읽으며 책출간을 오매불망 기다렸습니다.
    정말 고생 많으셨구요~ 탈고 축하드립니다~~
    즉시 구매 예정!!! 매우 기대하구 있습니다~ 하루빨리 출판되었으면 좋겠네요^^

  3. bear 2011/12/05 08:05 댓글주소 | 수정 | 삭제 | 댓글

    우와~~~ 늘 오가며 목이빠져라 기다렸습니다^^
    정말 수고하셨습니다..... 출간까진 좀 느긋하게 기다릴께요^^

  4. 꿀보 2011/12/05 09:16 댓글주소 | 수정 | 삭제 | 댓글

    고생하셨습니다. 축하드리구요~^^
    책을 쓴다는 것은 정말 어려운 일인것 같은데 멋지십니다.~

  5. 그를위해 2011/12/05 09:30 댓글주소 | 수정 | 삭제 | 댓글

    수고하셨습니다. 블로그를 통해 많은 도움 받았는데...
    앞으로 책으로도 볼 수 있네요..^^.. 기대백배..^^

  6. iwillhackyou 2011/12/05 09:37 댓글주소 | 수정 | 삭제 | 댓글

    얼마나 고생하셨을지 느껴집니다. ^^.
    정말 기대됩니다...

  7. KMC 2011/12/05 11:27 댓글주소 | 수정 | 삭제 | 댓글

    수고하셨습니다^^
    기나긴 대장정의 막을 내리시는군요 ㅎ
    이 블로그 작년 초부터 봐오면서 댓글한번 안썼었는데 책 내용이 무지 기대 되고 그 동안의 블로깅 내용들의 노고가 엿보여서 진심으로 구매 할 의사가 있으며 축하드립니다^^//

  8. Ethobis 2011/12/05 14:13 댓글주소 | 수정 | 삭제 | 댓글

    수고하셨습니다!
    진짜 오래 기다렸네요!! ㅋㅋㅋ.. 이거이거 이제 리버싱을 공부하려는 초심자들의
    평균 레벨이 올라갈것 같은 느낌입니다! ㅋㅋㅋㅋ
    기대기대! 두권사서 한권은 보관용 한권은 보는 용으로 써야겠습니다 ^_^

  9. HS 2011/12/05 14:34 댓글주소 | 수정 | 삭제 | 댓글

    수고하셨습니다~~^^살포시 기대를 해봅니다~~ :))

  10. 호지니 2011/12/05 14:47 댓글주소 | 수정 | 삭제 | 댓글

    우와~ 정말 기대되는 책입니다.
    싸인 준비 해두세요 ^^

  11. zxh 2011/12/05 15:33 댓글주소 | 수정 | 삭제 | 댓글

    출간되면 꼭 사서 읽어야겠네요!! 기대됩니다

  12. sun 2011/12/05 18:01 댓글주소 | 수정 | 삭제 | 댓글

    수고하셨습니다~~~^^ 너무너무 기대됩니다^^

  13. SAMSA 2011/12/05 19:23 댓글주소 | 수정 | 삭제 | 댓글

    Good !

  14. bbangdenge 2011/12/05 20:13 댓글주소 | 수정 | 삭제 | 댓글

    정말 고생하셧습니다 ㅎ 감사하구여
    리버싱에 너무 관심이 많아 자주 블로그도 들렸는데 이번에 책두 꼭사서 보겠습니다 ㅎ

  15. J 2011/12/06 15:39 댓글주소 | 수정 | 삭제 | 댓글

    그간 정말 고생 많으셨습니다. ^^
    무사히 마치신 후의 성취감과 벅찬 감동이 저에게도 느껴질 정도군요.
    게다가 나름대로 이 블로그를 방문하셨던 분들도
    함께 기다린 만큼 벅찬 기대감으로 와닿는 것 같습니다.

    부디, 블로그를 통한 공동구매와 퇴고과정에서 경험하셨듯이
    독자들의 가독성 향상과 저자의 생각이 독자들에게 전달되는데 있어서
    주변 상황과 공간의 제약을 받지 않도록
    책으로 출판하는 것외에도 전자문서로의 출판도 생각해 주셨으면 합니다.

    아마 1000페이지 분량이면 출퇴근시간에 들고다니기에는 무리가 있을것 같아서요. ^^
    (물론, 새로운 것을 배운다는 즐거움에 비하자면 감수할 수 있겠습니다만.. ㅎㅎ)

  16. Good Job! 2011/12/06 20:43 댓글주소 | 수정 | 삭제 | 댓글

    저는 오늘 처음 들어와봤는데 정말 알찬내용이 많은 꿀 블로그인거 같습니다! 책 나오면 꼭 사고 싶습니다~책 나오면 바로 올려주세요.ㅎㅎ

  17. 철이 2011/12/07 05:51 댓글주소 | 수정 | 삭제 | 댓글

    정말로 고생 하셨습니다. 주옥 같은 글들이 많겠네요.

    많은 광고 해드리겠게요 ㅠ

  18. 달봉아 2011/12/07 19:13 댓글주소 | 수정 | 삭제 | 댓글

    1년넘게 기다렸네요 이제나 저제나 언제 나오나 시간날때마다 체크했는데 오늘이 그날이군요
    정말수고 하셨습니다! 꼭 사볼게요 ^^

  19. reversecore 2011/12/07 21:21 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요~ ReverseCore 입니다.

    위에 댓글 달아주신 모든 분들께 감사 드립니다.

    여러분들의 관심과 응원으로 잘 끝마칠 수 있었습니다.

    너무 감사합니다.

  20. koromoon 2011/12/07 22:59 댓글주소 | 수정 | 삭제 | 댓글

    정말로 고생이 많으셨습니다...
    항상 블로그의 좋은 내용으로 인해서 감사했는데
    이렇게 좋은 책이 나올줄이야... ㅠㅠ
    꼭 사서 보고 싶습니다...
    항상 좋은 일만 가득하길 바랍니다...
    감사합니다... revesecore님...

  21. RUIN 2011/12/08 18:58 댓글주소 | 수정 | 삭제 | 댓글

    캬~ 수고 하셧습니다.
    입대 하기전부터 기대하던 책이었는데 입대 후에 지금 탄생햇군요!! 책이 저보다 더 짬 되는듯...
    내년에 볼 수 있을듯합니다 +_+

  22. modagi 2011/12/08 23:32 댓글주소 | 수정 | 삭제 | 댓글

    정말 축하드리고 감사드립니다. :)
    저도 기대가 컸던 만큼 이 소식이 아주 반갑고 기쁩니다. 감사합니다.

  23. lasthit 2011/12/09 07:55 댓글주소 | 수정 | 삭제 | 댓글

    멋지시네요. 인생의 꿈중 하나가 책을 써보는것인데 그걸 이루신분을 보니
    허용할수 없을 정도로 부럽습니다. 정말 축하드리고 책 제목도(?) 기대되네요.

  24. manlds 2011/12/09 11:19 댓글주소 | 수정 | 삭제 | 댓글

    와... 진짜 기다리던 책중에 하나 입니다. 올해 초 블로그 방문후 내용이 너무 좋아 매일 꾸준히 방문하고 있습니다. 이해 안되는 것은 보고 또 보고 하니 정말 도움이 되더라고요. 댓글 내용도 충실히 달아주시던데 댓글 내용도 많은 도움이 되었습니다.
    어서 출판일이 왔으면 좋겠네요. 수고하셨습니다.
    앞으로도 많은 지식전수 부탁드려요!

  25. 찡구 2011/12/09 12:07 댓글주소 | 수정 | 삭제 | 댓글

    어서 책이 나왔으면 좋겠네요 ㅜ.ㅠ
    ( 기다리고있어요~ :) )
    고생많이 하셨어요~~

  26. hcscp 2011/12/09 18:07 댓글주소 | 수정 | 삭제 | 댓글

    오오,,군대에서부터 간간히 들리던 곳인데,
    드디어 책이 나오는건가요!!너무 기대되요 ㅠㅠ 나오자 마자 살겁니다.

  27. 감염오리 2011/12/10 00:00 댓글주소 | 수정 | 삭제 | 댓글

    우리나라에는 리버스 엔지니어링 관련 책이 거의 없는 실정인데 ㅎㅎ

    나오면 저도 바로 살꺼예요^^ 빨리 나왔으면 좋겠네요

    아! 그런데 디스어셈블러는 뭘 사용해서 리버싱을 하실건지...

  28. RH 2011/12/10 17:07 댓글주소 | 수정 | 삭제 | 댓글

    드디어 기다리고 기다리던 리버스코어님의 책이 나오는군요

    와,, 정말 기대하고 있습니다.

    나오면 당장 구매를 ㅎㅎ

  29. 방문자 2011/12/11 00:45 댓글주소 | 수정 | 삭제 | 댓글

    질문있는데 책이 나오게되면 페이지 올칼라인가요?
    가격이 후덜덜하겠느넫,,,

  30. 세의 2011/12/11 19:04 댓글주소 | 수정 | 삭제 | 댓글

    기대하던 희소식입니다! 꼭꼭 사서 보겠습니다. ㅠ_ㅠ

  31. 박모씨 2011/12/11 21:05 댓글주소 | 수정 | 삭제 | 댓글

    오호...책으로 나오는군요.....꼭 사보고 싶어요.
    내나이 40에 리버싱을 배워야 하는 현실이 슬프군요...
    근데 이해하기 쉽게 잘 쓰신거 같아요.

  32. BBB 2011/12/12 16:19 댓글주소 | 수정 | 삭제 | 댓글

    이야!@!@!@
    컴퓨터를 많이하니깐 눈아파서 ㅜ 책으로 보고싶었는데 !!
    나오면 바로 사서 공부해야겠네요@!@!@!@!@!#!~#~!#

  33. kimms 2011/12/13 14:36 댓글주소 | 수정 | 삭제 | 댓글

    기대기대기대 하고 있습니다~~

  34. itsohard 2011/12/13 21:50 댓글주소 | 수정 | 삭제 | 댓글

    우와!!!!!!!!!!!!!! 너무 기대하고 있어요 이번 방학은 이 책으로 불태워야 겠군요 ㅎㅎ

  35. 고로아기 2011/12/14 09:16 댓글주소 | 수정 | 삭제 | 댓글

    정말 많이 기대하고있었는데; 요번 방학 때 ㅠ.ㅠ;;; 꼭 보고싶습니다...

  36. -=twopark=- 2011/12/14 14:39 댓글주소 | 수정 | 삭제 | 댓글

    수고하셨슴당. 출간이 기대되는군요.

  37. ^^리버스 공부 2011/12/14 20:33 댓글주소 | 수정 | 삭제 | 댓글

    정말 수고 많으셨습니다.^^
    많이 많이 팔리기를 저도 기대하겠습니다 .

  38. 니티 2011/12/15 08:46 댓글주소 | 수정 | 삭제 | 댓글

    정말 기대 됩니다^^) 저도 책 출간할때 19개월정도 걸린거 같은데, 정말 써본 사람만이 겪는거 같아요.
    1000페이지 안에 엄청난 내공이 묻어 있을거 같네요 홧팅!!!^^)

  39. 아메리카노냠냠 2011/12/15 11:24 댓글주소 | 수정 | 삭제 | 댓글

    책 언제 나오나요?? 애타게 기다리고 있는 1인.^^;;

  40. d 2011/12/17 03:15 댓글주소 | 수정 | 삭제 | 댓글

    d

  41. 가비 2011/12/17 19:53 댓글주소 | 수정 | 삭제 | 댓글

    와! 정말 수고하셨습니다. ^^
    분량이 정말 후덜덜하네요....;;
    출판되면 반드시 사서 보도록 하겠습니다.
    이 책이 우리나라의 IT 발전에 큰 기여를 하게 될 것 같습니다.

  42. 몽팡시에르 2011/12/18 15:29 댓글주소 | 수정 | 삭제 | 댓글

    리버스 코어 블로그를 눈팅만 한지 거의 1년이 되어가는데 그동안 속으로 정말 기다렸던 책입니다..

    코어님게서 책에 대해서 블로그에 언급을 안하시길래

    조용히 책 제작을 포기 하신줄 알았습니다...ㅎㅎㅎㅎ

    책이 나오면 100% 살겁니다....정말 입니다...ㅋㅋㅋ

    그동안 정말 고생하셨구욤...

    앞으로 코어님 팬 할랍니다....ㅎㅎㅎ

  43. 2011/12/20 11:33 댓글주소 | 수정 | 삭제 | 댓글

    비밀댓글입니다

  44. 비밀 2011/12/20 14:03 댓글주소 | 수정 | 삭제 | 댓글

    정말정말 축하드리고 감사드립니다!
    책으로 출간되면 정말 좋겠다고 생각했는데, 제 일인것처럼 너무나 기쁜네요.
    출고되면 꼭 알려주세요!!

  45. 비밀 2011/12/20 14:09 댓글주소 | 수정 | 삭제 | 댓글

    아. 책 제목 생각해 두셨다고 하셨는데.
    개인적으로.. "해킹의 미학" 이런 유치한게 아닐거라고 생각합니다.. ㅋ
    '해킹' 이라고 되어 있으면, 왠지 사려다가도 꺼려지더라고요...........................

  46. reversecore 2011/12/21 01:11 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요.

    제 책을 기대해 주시는 모든 분들께 감사드립니다. ^^~

    출간 일정이 잡히면 공지해 드리겠습니다.

    감사합니다.

  47. 책을보면서 2011/12/21 09:12 댓글주소 | 수정 | 삭제 | 댓글

    정말로 빨리 나왔으면 좋겠습니다. ㅎ

    너무너무 기대가 됩니다.!!!

    출판일이 빨리 결정되었으면..ㅎ

  48. LazyZombie 2011/12/21 12:25 댓글주소 | 수정 | 삭제 | 댓글

    너무 기대됩니다. 책 제목은 정해졌나요?? 꼭 사보겠습니다!

  49. 드레 2011/12/21 12:30 댓글주소 | 수정 | 삭제 | 댓글

    정말 기대 많이하고 있습니다. 하루 빨리 책이 나왔으면 좋겠습니다.
    완전 머스트 해브 아이템!!!

  50. K;nG 2011/12/24 16:34 댓글주소 | 수정 | 삭제 | 댓글

    3월안에는 구매를 희망하는데, 언제 쯤 출간이 될지 알 수 있을까요?

  51. 학수고대 2011/12/27 05:00 댓글주소 | 수정 | 삭제 | 댓글

    이 블로그에 거의 1년동안 오면서 이 책이 나오기를 기다렸던 이중의 한 사람입니다.
    정말 수고하셨습니다.

  52. hcscp 2011/12/27 10:30 댓글주소 | 수정 | 삭제 | 댓글

    책 초판 나오자 마자 바로 구매하고 싶네요 ㅎ

  53. No.190 2011/12/27 15:31 댓글주소 | 수정 | 삭제 | 댓글

    책 나오기만을 기다리고 있겠습니다!-_-
    총알 장전 완료.

  54. sisio07 2011/12/28 14:22 댓글주소 | 수정 | 삭제 | 댓글

    오 기대 하고 있습니다.

    책 나오기만을 기다리고 있습니다.

    리버싱 책이 매우 급합니다. 빨리 출간좀

  55. $Zero 2011/12/28 16:37 댓글주소 | 수정 | 삭제 | 댓글

    오랜만에 들렀는데 이제서야 소식을 접하네요
    책을 출판하신다니!! 정말 오래 기다렸습니다 ㅎㅎ

    앞으로도 좋은 책 많이 써주세요~~

  56. 짐승남 2012/01/02 13:13 댓글주소 | 수정 | 삭제 | 댓글

    언제 만나볼수 있는건가요?... 일정이라도 좀 알려주세요.

  57. Mr.Smurf 2012/01/03 10:20 댓글주소 | 수정 | 삭제 | 댓글

    언제쯤 만나 볼 수 있나요 예약 구매 하겠습니다~

  58. 신정우 2012/01/05 03:35 댓글주소 | 수정 | 삭제 | 댓글

    정말 책이 기다려집니다.
    문득 님께서 고생하신 3년 시간동안
    저는 뭐하고 있었는지 반성이 되네요.
    감사합니다.
    새해복많이 받으세요.

  59. 김태형 2012/01/05 13:38 댓글주소 | 수정 | 삭제 | 댓글

    정말 기대많이 하고있습니다 책나오면 바로 사야하겠네요

  60. 김태형 2012/01/05 13:39 댓글주소 | 수정 | 삭제 | 댓글

    정말 기대많이 하고있습니다 책나오면 바로 사야하겠네요

  61. 뚜기 2012/01/06 17:31 댓글주소 | 수정 | 삭제 | 댓글

    빨리 만나보고 싶어요~~~

  62. db_click 2012/01/07 17:59 댓글주소 | 수정 | 삭제 | 댓글

    다음휴가 때 꼭 사보겠습니다!

  63. keine__ 2012/01/08 15:15 댓글주소 | 수정 | 삭제 | 댓글

    반드시 사서 공부하고싶소!!

  64. smartsnake 2012/01/11 19:19 댓글주소 | 수정 | 삭제 | 댓글

    언제쯤 나오는겁니까!!! 너무 기다려져서 미치겟습니다!!!!
    기다리기 힘든 책은 딱 2번잇엇는데 3번째가 되는군요!!

  65. 질문이용 2012/01/14 11:39 댓글주소 | 수정 | 삭제 | 댓글

    책.. 처음 입문자도 볼수 있는건가요? 아니면 좀 초보자부터 보는건가요?
    리버싱이라는걸 근 3년전에 알았는데.... 선듯 손이 않가다가.. 또 새해가 오니.. 리버싱이라는걸
    공부해보면 어떨까..(취미로)

    리버싱 진입장벽이 너무 높자나요... 책도 거의 없고....

  66. 질문이용 2012/01/14 11:39 댓글주소 | 수정 | 삭제 | 댓글

    책.. 처음 입문자도 볼수 있는건가요? 아니면 좀 초보자부터 보는건가요?
    리버싱이라는걸 근 3년전에 알았는데.... 선듯 손이 않가다가.. 또 새해가 오니.. 리버싱이라는걸
    공부해보면 어떨까..(취미로)

    리버싱 진입장벽이 너무 높자나요... 책도 거의 없고....

  67. 질문이용 2012/01/14 11:39 댓글주소 | 수정 | 삭제 | 댓글

    책.. 처음 입문자도 볼수 있는건가요? 아니면 좀 초보자부터 보는건가요?
    리버싱이라는걸 근 3년전에 알았는데.... 선듯 손이 않가다가.. 또 새해가 오니.. 리버싱이라는걸
    공부해보면 어떨까..(취미로)

    리버싱 진입장벽이 너무 높자나요... 책도 거의 없고....

  68. 2012/01/14 21:24 댓글주소 | 수정 | 삭제 | 댓글

    비밀댓글입니다

  69. 으아아 2012/01/15 01:36 댓글주소 | 수정 | 삭제 | 댓글

    으아 기다리다 미치겠네. 빨리 사고 싶다아아

  70. 박싱데이 2012/01/16 13:38 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요.
    포스팅하신 글중에 IE 접속제어글을 따라서 해보고 있는데요. 이게 Windows7 에서는 잘됩니다만 XP 에서는 IE 의 메뉴가 모두 없어지거나(주소입력창도 사라짐), 다른 프로그램이 실행되지 않거나, explorer.exe 가 죽는등의 문제가 있는것 같습니다. 원인을 파악해 보려고 했는데..... 털썩..역시 제 실력으로는 ㅠㅠ.. 무엇이 문제일까요? 가르침 부탁 드리겠습니다.
    추신 : 너무 잘 정리해 주셔서 공부 잘하고 있습니다.^^

  71. daniel 2012/01/17 21:07 댓글주소 | 수정 | 삭제 | 댓글

    요즘 열심히 방문해서 공부하고 있습니다.

    기다려 집니다. 책이 빨리 나왔으면 좋겠네요.

  72. 노랑두꺼비 2012/01/18 11:56 댓글주소 | 수정 | 삭제 | 댓글

    책 어디서 사요~~~~? 출판사 및 발간시기를 알려주세요...
    사고 싶습니다 저도 빨리 고수가 되고 싶습니다~

  73. SeHwa 2012/01/19 07:55 댓글주소 | 수정 | 삭제 | 댓글

    드디어 나오는군요.
    구입 준비 완료입니다.

  74. kwsjjang8 2012/01/22 07:47 댓글주소 | 수정 | 삭제 | 댓글

    책 언제쯤 나오나요????? 중간 공지좀 부탁드려요~!@~새해복 많잉 받으세요

  75. 빵집상인 2012/01/25 11:31 댓글주소 | 수정 | 삭제 | 댓글

    기대되네요 ㅋㅋ
    좋은 글 정말 감사합니다~

  76. 기다리다 지친다 2012/01/25 20:38 댓글주소 | 수정 | 삭제 | 댓글

    지쳐서 다른책 하나 샀음.아으으앙

  77. 기초 2012/02/03 00:43 댓글주소 | 수정 | 삭제 | 댓글

    기다리고 있습니다. 언제쯤 나오는건지 ㅜㅜ

  78. arkanoid 2012/02/03 10:48 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요. 오랜만에 리버싱 관련 글들을 검색해보다 여기에 오게 되었습니다. 사실 처음 공부할 때는 리버싱이 되게 재미있는데, 시간이 흐르고 이런저런 다른 일들을 하다보니 옛날만큼 리버싱에 많은 시간을 투자하지 못하네요. 책을 출판하신다니 정말 열정이 대단하시고 고생이 많으셨을 것 같습니다. ^^

  79. 현기증 2012/02/08 15:30 댓글주소 | 수정 | 삭제 | 댓글

    아오! 현기증 나네요!!
    도대체 언제 출판되는거에요???? ㅋ

  80. reversecore 2012/02/08 23:22 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요.

    출판사에 원고를 넘겼구요.
    책이 편집/출판 되려면 아직 시간이 많이 필요합니다.

    기다리다 지치시는 분들께 너무 죄송합니다.
    기다리시고 기대하시는 분들이 너무 많으셔서 제가 다 마음이 안절부절입니다.

    대신 책이 출판되기 전까지 블로그에 더 재밌는 컨텐츠를 제공할 계획입니다.
    새로운 컨텐츠를 기대해 주세요~~~ ^^

    감사합니다.

  81. cqstudent1 2012/02/09 19:20 댓글주소 | 수정 | 삭제 | 댓글

    용기 얻고 갑니다..

  82. 기대 2012/02/10 01:21 댓글주소 | 수정 | 삭제 | 댓글

    새로운 콘텐츠라 많이 기대되네요
    물론 리버싱 내용이겟지요.
    빨리 시작하시길...



기존 InjDll.exe 유틸리티를 업그레이드(Ver. 1.1.1) 하였습니다.

  1. 64bit 지원

  2. <dll path> 의 상대 경로 지원


☞ InjDll.exe - DLL Injection/Ejection 전용 도구


Windows 7 64bit OS 가 보급됨에 따라 리버싱 분야에도 점차 64bit 지원 여부가 중요한 이슈가 되고 있습니다. 저 또한 최근에 64bit 관련 내용을 공부하면서 흥미로운 내용을 많이 접하였습니다. (이번에 작업 중인 리버싱 책에 64bit 리버싱 챕터를 추가시켰습니다.)

각 플랫폼(32/64bit) 별로 Dll Injection 을 하실 때 다음의 내용을 주의해 주시기 바랍니다.

- Target 프로세스가 32bit 인 경우 : Injector & Dll => 모두 32bit (PE32 포멧)
- Target 프로세스가 64bit 인 경우 : Injector & Dll => 모두 64bit (PE32+ 포멧)

* 64bit OS 에서는 32/64bit 프로세스가 모두 실행 가능하므로, Target 프로세스의 PE 포멧을 확인 하신 후 적절한 Injector(InjDll32/InjDll64) 와 DLL 을 사용하시면 됩니다.

* PE32+ 포멧의 파일을 생성하시려면 Visual C++ 2010 Express & Windows SDK 를 설치하시면 됩니다.


ReverseCore

Trackback Address :: http://www.reversecore.com/trackback/93 관련글 쓰기

  1. 퓨틱 2010/10/31 10:42 댓글주소 | 수정 | 삭제 | 댓글

    1등이군요 하하
    좋은 자료 감사합니다!

  2. 천세진 2010/11/01 09:54 댓글주소 | 수정 | 삭제 | 댓글

    업데이트에 감사드립니다.

    또한 의견을 반영해주심에 더욱 더 감사드립니다.
    참고로 64-bit PE32+를 생성하고 싶지만 저처럼 가난하신 분들은
    Windows Server 2003 SDK를 사용하셔도 됩니다.

    • reversecore 2010/11/03 00:21 댓글주소 | 수정 | 삭제

      안녕하세요.

      2003 SDK 에서도 되는군요? 좋은 정보 감사합니다. ^^

    • stares 2011/01/27 13:05 댓글주소 | 수정 | 삭제

      천세진님 혹시 그 옛날에 winapi32 assembly강좌 쓰신분 아니신가요??~

    • 천세진 2011/02/03 14:40 댓글주소 | 수정 | 삭제

      //stares님

      네, 2000년 초반에 Win32 API Assembly에 대해서 잠시 썼습니다.. ^^;
      나중에 보니 너무 허접하고 잘못된 내용도 있어서
      제 웹사이트에서는 해당 강좌를 지웠던 기억이 있네요..

      기억해주시니 감사합니다.

    • Stares 2011/02/04 19:53 댓글주소 | 수정 | 삭제

      흠..그거 재밌게 읽고있엇는데 말이죠..

      5개의 강좌만 쓰여진게 끝인가요?
      필요햇는데....

  3. 또다른D 2010/11/02 11:44 댓글주소 | 수정 | 삭제 | 댓글

    언제쯤 책이 나올지 궁금하네요.

    요즘 리버싱에 관심이 생겨서 여러 서적을 접하고 있는데,
    생각보다 어렵네요.

    reversecore님의 책이 쉽고 자세하게 풀이해줄거라 기대하고 있어요!!

    올가을까지라는 글을 얼핏 봤는데 이제 나올때가 된걸까요?? 기대기대~

    • reversecore 2010/11/03 00:19 댓글주소 | 수정 | 삭제

      원래 가을까지 할 수 있을꺼라 생각했는데요.

      추가되는 분량이 급격히 늘고, 완성도를 높이기 위해 일정이 훨씬 늘어났습니다. ^^

      기대해주시는만큼 높은 완성도를 갖춰서 출시하도록 하겠습니다.

      감사합니다. ^^

  4. 2010/11/04 16:12 댓글주소 | 수정 | 삭제 | 댓글

    비밀댓글입니다

    • reversecore 2010/11/06 00:24 댓글주소 | 수정 | 삭제

      안녕하세요.

      pRemoteBuf 에는 "myhack.dll" 문자열이 쓰여지는 것입니다. myhack.dll 자체를 쓰는 것이 아니구요.

      myhack.dll 은 타겟 프로세스에서 LoadLibrary() 를 호출하면 그때 로딩됩니다. Injector 쪽에서는 myhack.dll 의 로딩 주소를 미리 예측 하기 어렵지만, 일단 로딩되면 로딩 주소를 구해올 수 있습니다. (CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID); API 사용...)

      이제 타겟 프로세스에서 myhack.dll 이 어느 주소에 로딩되었는지 알았으니... WriteProcessMemory() API 로 데이터를 변경할 수 있습니다.

      감사합니다.

  5. 낭만고양이 2010/11/12 15:34 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요. 리버스님 항상 양질의 포스팅에 감사드리고, 올려놓으신 포스팅이 참 많아서
    정독하는데 정말 오래 걸렸습니다..^^물론 시간가는줄도 모르고 흥미있게 읽었는데요..
    64 버전업에서 궁금한게 있어서 이렇게 눈팅만 하다 죄송스럽게 글을 올립니다..
    x64 OS를 지원하는 인젝터와 DLL은 단순히 32 OS에서 동작하는 코드를 그대로 x64
    컴파일러로 컴파일 하신건지 아니면 내부 소스 또한 x64에 맞춰 바뀌는지 궁금해서 질문
    드립니다.. 그리고 책발매는 언제쯤인지도요.. 날씨가 변동이 심하네요.. 건강 조심하시고, 늘 좋은 포스팅 기대하겠습니다..__*

    • reversecore 2010/11/15 02:49 댓글주소 | 수정 | 삭제

      안녕하세요.

      하나의 소스로 32/64 를 빌드 시킨 것입니다.

      위 경우에는 소스 변경이 거의 없었습니다만...
      일반적으로는 32->64 포팅할 때 주의사항들이 있으므로...
      인터넷으로 검색하셔서 관련 내용을 숙지하시는 것이 좋습니다.

      책은 내년 2분기쯤으로 예상합니다.

      감사합니다.

  6. 김추노 2010/11/16 12:45 댓글주소 | 수정 | 삭제 | 댓글

    리버스님 블러그너무 멋지고 좋아요.

    책빨리나와서 구입하고싶습니다.

    리버스님 화이팅!

  7. RUIN 2010/11/17 00:09 댓글주소 | 수정 | 삭제 | 댓글

    아 책 빨리 보고 싶은데.....ㅠㅠ개인적인 생각이지만
    책을 반으로 나누시는건 어떨지........
    part 1과 Part 2로.........
    그저 빨리 보고 싶은 마음에 한마디 해보았습니다.ㅎㅎ;;

  8. Nicegom 2010/11/26 13:03 댓글주소 | 수정 | 삭제 | 댓글

    어서 책 출판하셔요^^ 기다리는중입니다. ㅎㅎ;;

  9. 봉이 2010/11/29 14:57 댓글주소 | 수정 | 삭제 | 댓글

    core님의 양질의 포스팅은 계속 되어야 한다! 쭈~~욱!!!!

  10. RUIN 2010/12/03 13:01 댓글주소 | 수정 | 삭제 | 댓글

    도대체 책 언제 나와요 ㅠ_ㅠ
    책 Part 1 // Part 2로 나눠서 Part 1부터 먼저 내주셧으면 ㅠㅠ

    • reversecore 2010/12/03 16:14 댓글주소 | 수정 | 삭제

      안녕하세요.

      Part 1/2 를 생각해 봤는데요.

      현재로서는 한권에 다 넣는게 좋다고 생각중입니다.

      제 책을 기다려주셔서 감사합니다. ^^

      힘내서 열심히 작업할께요~

    • RUIN 2010/12/03 18:20 댓글주소 | 수정 | 삭제

      네ㅠㅠㅠ........

      최대한 빨리 써주신다면 감사 감사^_^

      감기 조심하세요^^

    • 두둥 2010/12/05 01:31 댓글주소 | 수정 | 삭제

      저도 책 기다리고 있어요..ㅜ.ㅜ

      요새 사이트에 자주 못들어 왔는데 다양한 정보를
      책으로 볼수있는 기회가 빨리 오기를 바랍니다.

    • reversecore 2010/12/10 11:55 댓글주소 | 수정 | 삭제

      네, ^^

      항상 신경써 주시는 두분께 감사드립니다.

  11. Saeglo 2010/12/24 17:48 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요.
    여기서 배운게 정말 많고 항상 잘 보고 있습니다.

    혹시 윈도우가 아닌 다른 OS에서의 리버싱은 다룰 생각이 없으신지 궁금합니다.

    예를 들어 리눅스의 시스템 콜 후킹 같은 -

    실은 제가 최근에 Mac에 대해 공부를 하고 있는데
    국내에서 Mac에 대한 정보는 찾기가 힘들어서
    혼자 공부하기 쉽지 않네요 ㅠㅠ

    • reversecore 2010/12/27 14:53 댓글주소 | 수정 | 삭제

      안녕하세요
      아직은 윈도우에만 집중하고 있구요~ 다른 플랫폼으로는 모바일(iOS, Android) 에 관심있는 정도입니다^^

  12. kaka 2010/12/27 20:39 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요.
    좋은 글 매일와서 보고 따라해 보고..ㅋㅋ 있습니다.
    일단 책을 좀더 기다려야 한다니..아쉽습니다.
    화이팅~하세요.

    질문인데요..
    올려 놓으신 소스로 win7(32비트) IE8에서 DLL 인젝션을 실행하면 인젝션은 잘됩니다.
    그런데 인젝션된 dll의 DLL_PROCESS_ATTACH 이벤트가 수행되지 않는건
    머가 문젠가요? IE를 관리자 권한으로 실행하면 원하는데로 되던데요...
    직접 인젝션을 시키거나 NewZwResumeThread()을 수행하나 마찬가지네요.

    이것저것 해봐도 DLL_PROCESS_ATTACH 이벤트가 실행되질 안네요 T___T;;

    • reversecore 2010/12/31 00:38 댓글주소 | 수정 | 삭제

      안녕하세요.

      어떤 소스 코드를 사용하셨나요?

      제 블로그에 몇 가지 버전의 InjDll 소스가 있습니다. @@~

      제가 http://www.reversecore.com/76 에 있는 InjDll64.exe 와 dummy64.dll 을 가지고 테스트 해보면 잘 되는데요.

      dummy64.dll 소스에 OutputDebugString() 을 추가해서 DbgView 로 확인하면 DLL_PROCESS_ATTACH 가 정확히 뜹니다.

      테스트하신 소스(혹은 실행파일)을 제게 보내주시면 확인해 드리겠습니다.

      감사합니다.

    • kaka 2011/01/03 09:52 댓글주소 | 수정 | 삭제

      새해 복 많이 받으세요..

      아.. 죄송합니다.
      정확히 질문을 하지 못했네요.
      iexplore.exe부모는 DLL_PROCESS_ATTACH가 말씀하신데로 정확히 뜨는데,
      자식 iexplore.exe에게는 DLL_PROCESS_ATTACH나 DLL_THREAD_ATTACH 이벤트가 발생하질 안습니다.

      인젝터는 reversecore님께서 올려놓으신 파일로 했습니다.

    • reversecore 2011/01/07 05:38 댓글주소 | 수정 | 삭제

      아~ iexplore.exe 의 child process 말씀이시군요.

      Global API Hooking 을 써야 하는데요.
      인젝션 시키는 DLL 에 global API Hooking 코드가 준비되어 있어야 합니다. 위 댓글에서 소개한 dummy.dll 에는 그런 기능이 없지요.

      http://www.reversecore.com/79 <- 요기 있는 redirect.dll 파일이 바로 그 파일입니다.

      redirect.dll 을 인젝션 하신 후 IE 의 탭을 마구 띄워서 child process 가 생성되는 순간 자동으로 인젝션이 되면서 DLL_PROCESS_ATTACH 가 뜹니다.

      DbgView 로 확인할 수 있도록 OutputDebugString() 으로 로그를 찍었습니다.

      * Win 7 32bit/64bit 에서 테스트 하였습니다.

      kaka 님께서도 새해 복 많이 받으세요~~~

      감사합니다.

  13. kaka 2010/12/30 17:51 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요.
    InjDll64.exe와 dummy64.dll로 win7 64 OS에서 테스트해보니
    notepad에 inject(dll_process_attach)후 자동으로 dll_process_detach되던데
    왜그럴까요?

    • reversecore 2010/12/31 00:41 댓글주소 | 수정 | 삭제

      역시 제 환경에서는 잘 되는데요.

      notepad 에 injection 성공하면 DLL_PROCESS_ATTACH 가 뜨고 바로 이어서 DLL_THREAD_DETACH 가 뜹니다. (원격 스레드가 종료되면서 뜨는거죠.)

      메일 주소를 알려주시면 OutputDebugString() 을 추가한 dummy64.dll 을 보내드리겠습니다. 다시 한번 확인해 보시기 바랍니다.

      * 간혹 보안 모듈에서 DLL Injection 을 막는 경우가 있습니다. 근데 그건 인젝션 자체를 막는 거라 올려주신 증상하고도 맞지 않네요.

      감사합니다.

  14. Reversing_H 2011/01/14 10:22 댓글주소 | 수정 | 삭제 | 댓글

    항상 잘보고 잘 배우고 있습니다.
    여기서 질문하나 드릴게요 ~

    제가 리버싱쪽으로 취업을 하고 싶은데,,
    리버싱쪽에서 뽑는거는 잘 못본듯 하고
    다른기술도 같이 병행해야하는 업무인지;

    이쪽에 대해 아는게 없어서 말이죠;;

    조언 부탁드립니다 ^^

    • reversecore 2011/01/14 11:50 댓글주소 | 수정 | 삭제

      안녕하세요.

      관리자가 아닌 리버싱 엔지니어를 말씀하시는 거라면...

      제가 알기로는 보안 분야뿐입니다.
      (AV 업체, 온라인 게임 업체...)

      간혹 보안 컨설팅 분야에서 리버싱 관련 지식에 대해 가산점을 부여한다는 얘기만 건네 들은적은 있네요~

      감사합니다.

  15. Reversing_H 2011/01/14 11:01 댓글주소 | 수정 | 삭제 | 댓글

    아,, 한가지더 ;
    보통 악성코드 분석에서 리버싱이
    쓰이는걸로 알고있는데

    그렇다면 악성코드 분석할때
    필요한게 리버싱과
    또 어떤분야가 필요한지
    알고싶습니다.

    질문여러개 드려서
    죄송합니다 ㅠ

    • reversecore 2011/01/14 11:54 댓글주소 | 수정 | 삭제

      회사마다 다르겠습니다만...

      악성코드 분석은 리버싱 지식만 있으면 됩니다. (이것만도 쉽지 않습니다.)

      추가적으로 악성 코드 자체의 지식, 보안 지식 등을 갖춘다면 면접에서 좋은 점수를 받을 수 있겠지요.

      사실 회사마다 사람 뽑는 기준(신규직원의 경우) 은 다 틀려서 말이죠. 어디는 학력을 중시하고, 어디는 성격/기질을 중시하고, 어디는 순수한 실력을 보기도 하고... 그렇답니다. ^^

      감사합니다.

  16. Reversing_H 2011/01/15 20:07 댓글주소 | 수정 | 삭제 | 댓글

    답변 정말 감사드립니다.
    그런데 한가지 더 질문드릴게요;;
    원래 제가 7년전쯤에 프로그래밍쪽이 너무 좋아서
    개발쪽으로 취업을 하려다가 우리나라의 개발직의 종사자분들의
    여러가지 이야기를 들어보니(뭐 IT쪽은 여건이 안좋은건 비슷하지만)
    흥미도 떨어지고 여차저차에서 아예 IT쪽에 손을 놓았다가
    보안쪽에 흥미를 갖고 다시 공부를 시작했습니다.
    하지만 보안이라는 분야에 대해 처음 접하고 보안자체도 워낙 종류가
    많더군요;; 그리고 신입이 바로 들어가기도 쉽지 않은 분야이구요.
    그래서 리눅스 계열의 서버쪽에 우선 취업을 해서 이직하려고 준비하던중에
    리버싱이라는 분야를 알게 됐고 매우 흥미를 가지게 되었습니다.
    정말 이건 충격자체였고, 바로 이거다라는 느낌을 받았습니다.
    하지만 이걸 알게된것이 얼마전이고 말 그대로 실력이 없습니다.
    목표는 리버싱 일을 하는게 제 목표이긴 하지만요.
    여기서 질문을 드리자면
    뭐 물론 제일 좋은것은 처음부터 리버싱 업무를 하는 곳에 취직하는게 제일
    좋겠지만,, 제가 여건상 돈을 벌어야 하기에;; 바로 들어가기에는
    시간적이 여유와 자금적 여유가 없어서 프로그래밍 쪽이나
    서버쪽에 먼저 취직을 해야 할듯 싶은데 ,
    추후 리버싱일을 하려면 개발직 쪽으로 가는것이 더 나을까요?
    또한 개발직 쪽으로 가더라도 개발직도 종류가 많은데
    보안솔루션 개발쪽으로 가는것이 더 좋은 선택인지
    많은 것이 고민됩니다.
    자꾸 질문드려서 죄송하구요;;
    그만큼 이곳을 알게되고 리버싱이란 것을 알게되서
    기쁘구요. 조언좀 주셨으면 좋겠습니다 .
    감사합니다 ^^

    • reversecore 2011/01/20 00:04 댓글주소 | 수정 | 삭제

      안녕하세요.

      사실 리버싱일을 하시려면 말그대로 리버싱쪽으로 취직을 하시는게 좋습니다.

      제가 처음 리버싱으로 취업할 때만 해도 국내에 리버싱을 하는 사람들이 없어서 거의 대부분 경력 개발자들을 뽑았습니다. 몇 달을 교육시켜서 실무에 투입했지요.

      요즘은 리버싱 인구가 많이 늘어나서... 회사도 신입을 뽑더군요... 신입들의 리버싱 경험도 상당하더군요. 경력을 뽑을때도 동종 업계의 리버싱 경력자를 뽑구요...

      저와 저희 회사의 사례를 소개해 드린거라서요...
      참고만 하시기 바랍니다.

      제 개인적으로는 개발/리버싱 모두 경험을 가지고 있는 것이 좋다고 생각합니다. (실제로 제가 그렇구요.)

      감사합니다.

  17. 아침햇살 2011/02/07 16:24 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요^^ 맨날 눈팅만하고...책나오길를 기다리는 사람입니다;;
    매번 조용히 글만읽고 댓글하나 없이 가다가....궁금한게 있어서 염치 없지만 이렇게 질문하나
    드리고 갑니다.

    32비트에서는 전역 후킹시에 ntdll!ZwResumeThread를 이용하면 앞으로 실행될 프로세스에 대해
    서도 모두 후킹이 가능한걸 알았읍니다.. 근데

    64비트에서는 실행되고 있는 프로세드들이 64비트 응용프로그램인지 32비트 응용프로그램인지를
    구분하여 따로 Injector와 DLL을 맞추서 인젝션을 해야 하더군요..

    예를 들어 저는 64bit OS에서 32비트 응용프로그램에만 인젝션을 시도할 예정인데요
    이게 앞으로 실행될 프로세스에 대해서 어떻게 인젝션을 해야 할지 좀 감이 안와서요;;
    쓰레드를 돌려서 새로 생성되는 프로세스를 감시하다가 32비트인지 64비트인지 구분해서 인젝션을 할까도 생각했지만 이건 왠지 아니다 싶은 생각이 들더군요;;
    64비트에서도 ntdll!ZwResumeThread 처럼 뭔가 핵심적인 함수 하나를 후킹해서 전역적으로 후킹할 수 있는 방법이 없을까 해서요.. 물론 저 함수를 64비트에서 후킹 할 수 있겠지만
    제가 돌리는 응용프로그램이 32비트이다보니 explorer.exe에 인젝션을 할 수 가 없는 상황입니다.
    다른 분들의 의견이나 reversercore님의 의견이 한번 듣고 싶네요..~ +.+
    구글링을 해봤지만 딱히 눈에 딱 보이는거 없어서요..(혹시 제가 놓친거 일 수도 있습니다..ㅋ)
    어떻게 생각하세요??

    • reversecore 2011/02/09 21:39 댓글주소 | 수정 | 삭제

      안녕하세요.

      64bit 환경에서 32bit 프로세스만 global hooking(자동 인젝션) 을 하신다는 말씀이시죠~

      제가 직접 시도해 보기 전에는 뭐라 말씀드리기가 어렵군요.

      테스트 후 다시 답변 달아드리겠습니다.

      감사합니다.

    • 아침햇살 2011/02/14 11:34 댓글주소 | 수정 | 삭제

      넵 답변 달아주셔서 감사합니다^^

      지금은 우선 쓰레드에서 프로세스를 감시하여 새로 생성된 프로세스
      를 탐지해 32bit일경우만 Injection하도록 작업하고 있습니다.^^

      좀더 좋은 방법이 나왔으면 좋겠네요~ ㅎ ~
      그럼 수고하세요^^

  18. baboha 2011/02/12 19:22 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요 리버스코어님 글 잘보고있습니다.

    질문이 하나있는데요

    프로세스가 실행중일때 Injection된 dll의 이름들을 얻을려면 어떻게 해야할까요?

    IAT에 써진것말고 프로세스가 LoadLibrary를 통해서 따로 Injection한 것까지 알고싶습니다

    마치 procexp 프로그램처럼요

    • reversecore 2011/02/18 22:44 댓글주소 | 수정 | 삭제

      안녕하세요.

      말씀하신 그런 기능을 수행하는 API 가 있습니다. Injection 된 DLL 들을 Ejection 시킬 때 사용됩니다.

      CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID)
      Module32First()
      Module32Next()

      위 API 를 검색해 보시기 바랍니다.

      감사합니다.

  19. harrison 2011/04/16 06:37 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요.
    리버싱 관련 지식이 필요해서 검색을 하다가 이곳에 왔는데,
    굉장한 도움이 도움이 되었습니다.
    감사합니다.

  20. wordboss 2011/05/17 10:47 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요.
    오늘 오랜만에 강좌에 와보니 새로운 내용 더 생겼네요.
    보 다 흥미로운 내용 더 많이 올려주세요
    자주 방문 하겠어요
    건강에 각별히 류의하시구요

  21. FreeAngel 2011/07/06 03:01 댓글주소 | 수정 | 삭제 | 댓글

    궁금한점이있는데요.ㅠㅠ 글로벌 후킹에ㅓ 실행되는 프로그램, 앞으로 실행될 프로그램을
    제어 할 수 있다고했는데, 흰트조금만주세요.ㅠㅠ 크레이트 프로세스를 써서하는건지;;;;ㅠ

    • reversecore 2011/07/14 05:56 댓글주소 | 수정 | 삭제

      안녕하세요.

      제 블로그에 있는 글이 도움이 되실 것 같습니다.

      Advanced Global API Hooking – IE 접속 제어 (1)
      (http://www.reversecore.com/77)

      API Hooking – '스텔스' 프로세스 (1)
      (http://www.reversecore.com/65)

      감사합니다.

  22. 2011/10/27 10:49 댓글주소 | 수정 | 삭제 | 댓글

    비밀댓글입니다

  23. 2011/10/28 12:51 댓글주소 | 수정 | 삭제 | 댓글

    비밀댓글입니다

  24. 2011/10/28 12:51 댓글주소 | 수정 | 삭제 | 댓글

    비밀댓글입니다

  25. 2012/01/09 02:04 댓글주소 | 수정 | 삭제 | 댓글

    비밀댓글입니다

    • reversecore 2012/01/11 06:17 댓글주소 | 수정 | 삭제

      안녕하세요.

      와~ 대단하세요.
      그토록 분명한 꿈을 갖고 계시니 꼭 이룰 수 있을 거라 생각합니다.

      감사합니다.

  26. 따오기d 2012/02/01 10:45 댓글주소 | 수정 | 삭제 | 댓글

    수고하십니다.!! 글잘봤어요
    질문이 있는데요
    Injector = 32bit process
    HookDLL = 64bit dll
    Target Process = 64bit Process
    OS 는 Windows 2008 R2 (64bit) 이구요
    이상황에서 Injector 가 wow 로 돌고있는 상황에서 가능한 방법이 있나요?



이전 강좌에서 이어지는 내용입니다. 

어셈블리 언어를 이용한 Code Injection (4)



# MessageBoxA() 파라미터 입력 1 – MB_OK

002D002C    6A 00         PUSH 0

PUSH 0 은 스택에 0 을 입력하는 명령입니다. 이 0 의 의미는 아래에서 호출될 MessageBoxA() API 의 네 번째 파라미터(uType)로 사용됩니다.

참고로 MessageBoxA() API 는 아래와 같이 4 개의 파라미터를 받습니다.

int WINAPI MessageBox(
  __in_opt  HWND hWnd,
  __in_opt  LPCTSTR lpText,
  __in_opt  LPCTSTR lpCaption,
  __in      UINT uType
);


* 참고
uType 값이 0 이면 MB_OK 를 의미하며, 단순히 OK(“확인”) 버튼 한 개만 보여주게 됩니다.


# MessageBoxA() 파라미터 입력 2 – "ReverseCore"

002D002E    E8 0C000000   CALL 002D003F
002D0033    52            PUSH EDX
002D0034    65:76 65      JBE SHORT 002D009C
002D0037    72 73         JB SHORT 002D00AC
002D0039    65:43         INC EBX
002D003B    6F            OUTS DX,DWORD PTR ES:[EDI]
002D003C    72 65         JB SHORT 002D00A3
002D003E    00E8          ADD AL,CH

이번에는 CALL 명령으로 코드 사이에 포함된 문자열 데이터 주소를 스택에 입력하는 기법을 소개하겠습니다. 이 역시 Assembly 프로그래밍 언어에서만 가능한 기법입니다.

위 2D0033 ~ 2D003E 주소 영역은 분명히 프로그램 코드 영역이지만 그 내용은 사실 "ReverseCore" 문자열 데이터 입니다. (붉은색 표시 부분) 즉, "ReverseCore" 문자열의 시작주소는 2D0033 입니다. 그리고 이 문자열은 MessageBoxA() API 의 세 번째 파라미터 (lpCaption)로 사용됩니다. 

함수 파라미터로 사용되려면 문자열 주소를 스택에 넣어줘야 하는데 과연 어떤 방식으로 입력할까요? 

2D002E 주소의 CALL 002D003F 명령을 디버깅으로 쫓아 들어가 보겠습니다. (StepIn [F7]) 그리고 아래 그림과 같이 스택 주소를 봐주시기 바랍니다.


<Fig. 13>

스택에 "ReverseCore" 문자열 시작 주소인 2D0033 이 입력되었습니다!!! MessageBoxA() 의 세 번째 파라미터가 입력된 셈이죠.

이 트릭은 CALL 명령어의 "동작원리"를 응용한 것입니다.

CALL 002D003F 명령을 수행하면 함수(2D003F) 가 종료된 후 돌아올 리턴 주소(2D0033)를 스택에 입력(PUSH)한 후 해당 함수 주소(2D003F)로 이동(JMP)합니다. 즉, CALL 명령어는 PUSH, JMP 명령어를 합쳐 놓은 것입니다. 

사실 2D003F 는 함수 형태가 아닙니다. RETN 명령어로 되돌아가는 형태가 아니란 얘기지요. 여기서의 CALL 002D003F 명령어는 바로 뒤에 이어지는 "ReverseCore" 문자열 주소를 스택에 입력하고 그 다음 코드 명령어로 가기 위해서 사용되고 있는 것입니다.

이해 되시나요? ^^ 재미있는 CALL 명령어 사용법입니다.


# MessageBoxA() 파라미터 입력 3 – "www.reversecore.com"

002D003F    E8 14000000   CALL 002D0058
002D0044    77 77         JA SHORT 002D00BD
002D0046    77 2E         JA SHORT 002D0076
002D0048    72 65         JB SHORT 002D00AF
002D004A    76 65         JBE SHORT 002D00B1
002D004C    72 73         JB SHORT 002D00C1
002D004E    65:636F 72    ARPL WORD PTR GS:[EDI+72],BP
002D0052    65:           PREFIX GS:
002D0053    2E:636F 6D    ARPL WORD PTR CS:[EDI+6D],BP
002D0057    006A 00       ADD BYTE PTR DS:[EDX],CH

역시 위 "ReverseCore" 문자열과 마찬가지로 MessageBoxA() API 의 두 번째 파라미터 lpText 문자열("www.reversecore.com")을 입력하는 명령입니다.

위 코드에서 빨간색으로 표시된 부분은 코드 명령어가 아니라 문자열 데이터("www.reversecore.com") 입니다. 

2D003F 주소의 CALL 002D0058 명령어는 (앞에서 설명 드린 바와 같이) 바로 뒤에 이어지는 문자열("www.reversecore.com") 데이터의 주소(2D0044)를 스택에 입력하고 그 다음 명령어 주소(2D0058)로 갑니다. (아래 그림 참고)


<Fig. 14>


# MessageBoxA() 파라미터 입력 4 – NULL

002D0058    6A 00         PUSH 0

MessageBoxA() API 의 첫 번째 파라미터인 hWnd 값을 입력합니다. 일반적으로는 메시지 박스가 소속된 윈도우 핸들을 입력하지만, 여기서는 NULL 을 입력하여 무소속(?) 메시지 박스가 출력되도록 만들겠습니다.


# MessageBoxA(NULL, "www.reversecore.com", "ReverseCore", MB_OK) 호출

002D005A    FFD0          CALL EAX

드디어 MessageBoxA() API 를 호출하는 CALL 명령어 입니다. 현재 EAX 레지스터에는 위에서 호출한 GetProcAddress() 에 의해서 리턴된 MessageBoxA() API 의 시작 주소(7793EA71)가 저장되어 있습니다. (<Fig. 12> 참고)

2D005A 주소의 CALL EAX 명령어까지 디버깅한 후 레지스터와 스택을 살펴보면 아래 그림과 같습니다.


<Fig. 15>

이 CALL EAX 명령어를 실행하면 메시지 박스가 나타날 것입니다.


<Fig. 16>


# ThreadProc() 리턴값 세팅

002D005C    33C0          XOR EAX,EAX

notepad.exe 프로세스에 인젝션된 코드(ThreadProc() 스레드 함수) 가 종료될 준비를 합니다. 스레드 함수의 리턴값을 0 으로 세팅하기 위해서 XOR EAX, EAX 명령어가 사용됩니다. 함수의 리턴값은 EAX 레지스터를 사용한다는 것을 기억 하시죠?

* 참고
XOR EAX, EAX 명령어는 EAX 레지스터를 0 으로 초기화하는 가장 쉽고 빠른 명령어 입니다. 디버깅하면서 많이 접하게 될 것입니다.


# Stack Frame 해제 및 함수 리턴

002D005E    8BE5          MOV ESP,EBP
002D0060    5D            POP EBP
002D0061    C3            RETN

ThreadProc() 함수 시작할 때 생성한 Stack Frame 을 해제 합니다. 그리고 RETN 명령으로 함수가 종료됩니다.

이 ThreadProc() 함수에서 Stack Frame 은 매우 중요합니다. 앞에서 설명 드린 "PUSH 를 이용한 스택에 문자열 넣는 기법" 에서 스택에 입력된 문자열을 일일이 POP 명령으로 힘들게 없앨 필요 없이 Stack Frame 해제 명령어 한방으로 가볍게 초기화 시킬 수 있습니다.

* 참고
Stack Frame 관련 내용은 아래 링크를 참고하세요~


+--+

Assembly 언어를 이용한 Code Injection 에 관한 설명을 마치도록 하겠습니다. C 언어 보다 더 자유로운 Assembly 언어를 사용하여 다양하고 창의적인 코드를 생성해 보시기 바랍니다. Assembly 초보자도 OllyDbg 의 "Assemble" 명령어를 이용하면 좀 더 쉽게 이용하실 수 있습니다.

위 실습을 다 끝내신 분께서는 한번 제 블로그 이미지에 있는 바이트 코드를 입력해서 실행해 보시기 바랍니다. ^^ 어떤 코드가 나타날까요? (OllyDbg 의 편집 기능과 New Origin Here 기능을 사용하면 되겠지요~)


ReverseCore

위 글이 도움이 되셨다면 추천(VIEW ON) 부탁 드려요~

Trackback Address :: http://www.reversecore.com/trackback/88 관련글 쓰기

  1. 철이 2010/07/06 15:44 댓글주소 | 수정 | 삭제 | 댓글

    정말로 잘보았습니다 ㅎ

  2. sonickaka 2010/07/10 14:23 댓글주소 | 수정 | 삭제 | 댓글

    정말 좋은 포스팅 감사합니다 ^^
    코드 인젝션을 체계적으로 정리해볼수 있어서 너무 갚지네요.. ^^
    감사합니다~!

  3. 땅콩 2010/07/24 11:35 댓글주소 | 수정 | 삭제 | 댓글

    한번 꼭 다 봐야지 봐야지..하면서...계속 미루다가..방학이라서..
    매일보고 있습니다..ㅎㅎ (analysis..부분만..거의 다 본듯..)

    이렇게 좋은 자료를..날로 먹는거 같아서....

    암튼..너무 감사합니다...

  4. 2010/07/31 00:11 댓글주소 | 수정 | 삭제 | 댓글

    비밀댓글입니다

    • reversecore 2010/08/01 22:41 댓글주소 | 수정 | 삭제

      안녕하세요.

      비도덕적이고 불법적인 내용이 아니라면 제가 작은 도움을 드릴 수 도 있습니다.

      관련된 질문 있으시면 올려주세요~

      감사합니다.

  5. 2010/08/02 10:48 댓글주소 | 수정 | 삭제 | 댓글

    비밀댓글입니다

    • reversecore 2010/08/04 20:43 댓글주소 | 수정 | 삭제

      안녕하세요.

      PE Viewer 제작이야 말로 PE Header 공부의 완성판이라고 할 수 있지요. ^^

      제가 예전에 Assembly 로 개발한게 있긴 한데요... 소스를 공개할만한 수준은 아니라서요...

      그때 저는 Microsoft 의 Dumpbin 유틸리티를 참고해서 콘솔버전으로 만들었습니다.

      다른 소스는 가지고 있는게 없네요~

      요령이라고 할것도 없지만...
      그냥 편하게 Dumpbin 이나 PEView 같이 기본적인 정보를 나열하는 식으로 만드시면 됩니다.

      dbghelp.dll 에 기본적인 API 함수가 지원되기는 하지만 그보다는 파일 매핑을 사용해 직접 구현하시는 방법을 추천드립니다.
      (기본적인 구조체는 winnt.h 에 잘 정의되어 있구요...)

      감사합니다.

  6. gjuRlo 2010/08/04 10:06 댓글주소 | 수정 | 삭제 | 댓글

    8월 마소 강좌 코드 인젝션에 이끌러 이 홈페이지까지 왔다가 잘 보고 갑니다. 감사합니다~

  7. 땅콩 2010/08/06 13:19 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요 ..공부하다가 막히는 부분이 있어서 .글을 올립니다.

    사실은 데브피아에 글도 올려봤는데..답변이..없어서...이렇게 실례를 무릅쓰고...ㅜㅜ

    요즘 디바이스를 공부중에 잇는 학생입니다.



    ssdt 후킹을 해서 계산기를 프로세스를 종료를 못하게 했습니다..

    (zwterminateprocess를 후킹했습니다..)



    그런데..sdtrestore라는 http://www.security.org.sg/code/sdtrestore.html 여기서 받은걸로는 탐지를 못하는데

    (sdtrestore의 원리는 ntoskrnl.exe에서 정보를 바로 읽어온다고 알고 있는데....)



    하지만....icesword는 탐지를 했습니다..요 방법이 아주 궁금해서 글을 올립니다..



    과연 icesword의 탐지 방법을 무엇인지......



    답변 부탁드립니다. ㅎㅎ



    (제 실행환경은 xp에 sp3 입니다.

    • reversecore 2010/08/09 11:31 댓글주소 | 수정 | 삭제

      안녕하세요.

      후킹 탐지 방법은 후킹 방법처럼 무수히 많이 있답니다.

      저도 icesword 를 본적이 있습니다. 세부 동작 원리까지는 자세히 모르지만 매우 치졸한(?) 방법을 많이 사용했을 것입니다. ^^

      무슨 뜻이냐면... 후킹 탐지 되지 않기 위해서 별의별 기발한 기법들이 동원되는데요... 이를 탐지하는 입장에서도 똑같이 희안하고 무식하지만 확실한 (full scan 같은) 방법들을 동원하는 것입니다.

      커널 후킹은 고급주제이며 향후 제 블로그에 자세히 다룰 예정입니다.

      감사합니다.

  8. 땅콩 2010/08/09 14:26 댓글주소 | 수정 | 삭제 | 댓글

    옙..답변 감사드립니다..........원리를 분석하고 싶은데..아직 내공이 너무 부족하네요..ㅜㅜ

    빨리 블로그에서 글을 보았으면..좋겠습니다..ㅎㅎ

    수고하세요..ㅎ

  9. 봉이 2010/08/24 13:47 댓글주소 | 수정 | 삭제 | 댓글

    안녕 하세요!
    저두 마소에서 관련글보다 여기 왔는데, 정말 글을 잘쓰시는 거 같아요!
    코드인젝션편 보면서 그림과 올리디버거 사용방법등이 적절하게 나와 이해하기 좋았습니다.
    앞으로도 좋은 내용 기대할게요 ^^

  10. 엘군 2011/07/05 15:50 댓글주소 | 수정 | 삭제 | 댓글

    전 코드 인젝션에 대해 전혀 모르던 학생입니다ㅎㅎ
    dll 로딩 원리를 알고싶어서 구글링 하다가 우연히 봤는데 왜이렇게 재밌게 보이는지..!!
    요즘은 영상처리쪽 공부중인데요ㅎ 공부할 마음없었는데 기회되면 이분야도 해보고 싶네요!ㅋ
    책도내신것같은데 꼭 봐봐야겠습니다
    #덧, 좋은글 올려주셔서 감사합니다



다른 프로세스에 인젝션된 코드를 디버깅하면서 동작 원리를 알아보도록 하겠습니다.

이전 강좌의 내용은 아래 링크를 참조하시기 바랍니다.




notepad.exe 디버깅
notepad.exe 프로세스에 어셈블리 언어로 제작한 코드를 인젝션 시키고 디버깅을 해보도록 하겠습니다.

Code Injection 기법의 디버깅 방법은 아래 링크를 참고하시기 바랍니다.

위의 글에서 소개된 방법에 따라 notepad.exe 에 인젝션된 코드를 OllyDbg 로 보면 아래 그림과 같습니다. 


<Fig. 1>

* 참고
위 코드의 시작 주소(2D0000)는 사용자 환경에 따라서 틀려집니다.

위 코드를 자세히 디버깅 해보겠습니다.


# Stack Frame 생성

002D0000    55            PUSH EBP                         ; # ThreadProc()
002D0001    8BEC          MOV EBP,ESP

전형적인 스택 프레임 생성 명령어 입니다. 이 명령어가 낯 설은 분들께서는 이 기회에 "55 8BEC" 하고 외워두시는 것도 좋습니다. 

스택 프레임을 생성하는 이유는 이후에 나오는 명령어들이 스택에 문자열들을 집어넣는 기법을 사용하기 때문에 위 ThreadProc() 함수가 종료될 때 스택을 깨끗이 정리하기 위해서입니다.


# THREAD_PARAM 구조체 포인터

002D0003    8B75 08       MOV ESI,DWORD PTR SS:[EBP+8]

스택 프레임이 생성된 이후에 [EBP+8] 이 의미하는 것은 함수로 넘어온 첫 번째 파라미터 입니다. 이 경우에는 THREAD_PARAM 구조체 포인터가 될 것입니다. 

아래에 THREAD_PARAM 구조체를 표시하였습니다. 구조체의 멤버는 2개의 함수 포인터인데 각각 “LoadLibraryA” 와 “GetProcAddress()” 의 포인터가 저장됩니다. (누가 이 포인터를 구해서 저장시켜 줬을까요? 네, 지난 강좌에서 소개한 CodeInjection2.exe 프로그램에서 구해서 notepad.exe 에 인젝션 시킨 후 스레드 실행할 때 파라미터로 넣어주었죠.)

typedef struct _THREAD_PARAM 
{
    FARPROC pFunc[2];               // LoadLibraryA(), GetProcAddress()
} THREAD_PARAM, *PTHREAD_PARAM;

위 2D0003 주소의 MOV ESI, DWORD PTR SS:[EBP+8] 명령어를 실행한 이후에 ESI 레지스터에 저장된 주소를 따라가서 확인해 보겠습니다.


<Fig. 2>

ESI 에 280000 주소가 저장되었으며 이 주소는 CodeInjection2.exe 에서 THREAD_PARAM 구조체를 위해 notepad.exe 프로세스 메모리 공간에 할당한 메모리 버퍼의 주소입니다.

* 참고
THREAD_PARAM 구조체 주소(2D0000)는 사용자 환경에 따라서 틀려집니다.

<Fig. 2> 의 메모리 윈도우를 보면 280000 주소에 두 개의 4 byte 값들이 저장된 걸 확인할 수 있습니다. 저 값들이 "LoadLibraryA" 와 "GetProcAddress" API 함수의 시작 주소일 것입니다. 좀 더 직관적으로 확인하기 위해서 OllyDbg 메모리 윈도우의 보기 옵션을 변경해 보겠습니다.

메모리 윈도우에 커서를 위치시킨 후 마우스 우측 메뉴의 "Long – Address" 항목을 선택해 주시기 바랍니다.


<Fig. 3>

위 메뉴 항목을 선택하면 OllyDbg 의 메모리 윈도우는 아래 그림과 같이 표시 형식이 변경됩니다.


<Fig. 4>

주소가 훨씬 더 직관적으로 표시되지요? 또한 친절하게 Comment 에 각 주소에 해당되는 API 이름을 표시해 주고 있습니다.


# "user32.dll" 문자열

002D0006    68 6C6C0000   PUSH 6C6C         ; “\0\0ll”
002D000B    68 33322E64   PUSH 642E3233     ; “d.23”
002D0010    68 75736572   PUSH 72657375     ; “resu”

위 코드는 스택(Stack)에 문자열을 저장하는 기법입니다. 스택에 직접 접근할 수 있는 Assembly 프로그래밍 언어에서만 가능한 독특한 기법이지요. 

2D0006 주소의 PUSH 6C6C 명령어는 스택에 00006C6C 값을 저장하라는 뜻입니다. 6C 는 ASCII 로 'l' 이지요. 즉, 이 명령은 "\0\0ll" 문자열을 스택에 집어 넣는 것입니다. 

그 밑의 2D000B 와 2D0010 주소의 PUSH 명령어도 각각 "d.23" 문자열과 "resu" 문자열을 입력하는 명령어 입니다.

x86 CPU 의 Little Endian 표기법과 스택의 거꾸로 자라는 특성 때문에 문자열을 뒤집어서 입력하는 것을 주의 깊게 보시기 바랍니다. 이것은 디버깅할 때 잘 알고 계셔야 하는 내용입니다.

2D0010 주소까지 디버깅 한 후 스택을 보면 아래 그림과 같습니다.


<Fig. 5>

이와 같은 PUSH 명령어를 이용하여 원하는 문자열을 스택에 입력할 수 있습니다. 또한 Code Injection 할 때 문자열 데이터를 따로 인젝션 하지 않고 코드에 포함시켜서 코드만 인젝션 시킬 수 있습니다.

* 참고
  - 문자열 데이타를 코드에 포함시키는 방법은 한가지가 더 있으며, 뒤에서 따로 소개합니다.
  - 32 bit OS 에서 PUSH 명령어는 한번에 최대 4 byte 크기의 데이터만 스택에 저장이 가능합니다. 


# "user32.dll" 문자열 파라미터 입력

002D0015    54             PUSH ESP

LoadLibraryA() API 는 파라미터로 로딩시킬 DLL 파일 이름 문자열 주소를 받습니다. 

HMODULE WINAPI LoadLibrary(
  __in  LPCTSTR lpFileName
);


위 <Fig. 5> 를 보시면 현재 ESP 의 값은 219FCD4 이며 이것은 "user32.dll" 문자열의 시작 주소입니다. 따라서 2D0015 주소의 PUSH ESP 명령어는 "user32.dll" 문자열 주소(219FCD4)를 스택에 입력하는 명령입니다. (아래 그림 참고)


<Fig. 6>


# LoadLibraryA("user32.dll") 호출

002D0016    FF16          CALL DWORD PTR DS:[ESI]         ; kernel32.LoadLibraryA

ESI 레지스터는 <Fig. 4> 에서 보다시피 280000 값을 가지며 이 주소에는 LoadLibraryA() API 의 시작 주소(772C2864)가 저장되어 있습니다. 아래 그림을 봐주시기 바랍니다.
 

<Fig. 7>

어셈블리 언어의 메모리 참조 문법이 생소하신 분들께서는 이번 기회에 확실히 익혀 두시기 바랍니다. 아래와 같은 간단한 전개식을 사용하면 쉽게 이해하실 수 있습니다. ([ ] 는 C 언어의 포인터 참조와 같은 개념입니다.)

[ESI] = [280000] = 772C2864 (address of kernel32.LoadLibraryA)

2D0016 주소의 CALL DWORD PTR DS:[ESI] 명령어를 실행하면 LoadLibraryA() API 가 호출되면서 파라미터로 입력된 "user32.dll" 이 로딩됩니다. notepad.exe 프로세스는 실행될 때 이미 user32.dll 를 로딩하였으므로 그 로딩 주소만 리턴합니다.


<Fig. 8>

함수의 리턴값은 EAX 에 저장되므로 위 <Fig. 8> 을 보시면 EAX = 778E0000 이 저장되었습니다.

OllyDbg 메뉴의 "View – Executable modules [ALT + E]" 항목을 선택하시면 아래 그림과 같이 프로세스 메모리에 로딩된 DLL 을 확인 할 수 있습니다.


<Fig. 9>

위 그림에서 user32.dll 의 로딩 주소가 778E0000 임을 확인 할 수 있습니다.


# "MessageBoxA" 문자열

002D0018    68 6F784100   PUSH 41786F         ; “\0Axo”
002D001D    68 61676542   PUSH 42656761       ; “Bega”
002D0022    68 4D657373   PUSH 7373654D       ; “sseM”

역시 PUSH 명령어를 이용해서 문자열 "MessageBoxA" 를 스택에 입력하는 명령어 입니다. (위의 "user32.dll" 문자열 입력과 동일합니다.)

2D0022 주소의 PUSH 명령까지 디버깅을 하고 나면 아래 그림과 같이 스택에 "MessageBoxA" 문자열이 저장됩니다.


<Fig. 10>


# GetProcAddress(hMod, "MessageBoxA") 호출

002D0027    54            PUSH ESP                          ; - “MessageBoxA”
002D0028    50            PUSH EAX                          ; - hMod (778E0000)
002D0029    FF56 04       CALL DWORD PTR DS:[ESI+4]       ; kernel32.GetProcAddress

현재 ESP 의 값은 0219FCC8 입니다. (<Fig. 10> 참고) 따라서 2D0027 주소의 PUSH ESP 명령어는 "MessageBoxA" 문자열 주소(0219FCC8) 를 스택에 입력하는 명령입니다. (이 문자열 주소는 2D0029 주소에서 호출되는 GetProcAddress() API 의 2nd 파라미터로 사용됩니다.)

그리고 현재 EAX 의 값은 778E0000 입니다. 이는 user32.dll 모듈의 로딩 주소이지요. (<Fig. 8> 참고) 따라서 2D0029 주소의 PUSH EAX 명령어는 user32.dll 의 시작 주소(hMod)를 스택에 입력하는 명령입니다. (이 문자열 주소는 2D0029 주소에서 호출되는 GetProcAddress() API 의 1st  파라미터로 사용됩니다.)

여기까지 디버깅을 진행한 후 스택의 모습은 아래 그림과 같습니다.


<Fig. 11>

ESI 레지스터의 값은 280000 입니다. 따라서 [ESI+4] 의 전개식은 다음과 같습니다. (<Fig. 4>, <Fig. 7> 참고)

[ESI+4] = [280004] = 772C1837 (address of kernel32.GetProcAddress)

따라서 2D0029 주소의 CALL DWORD PTR DS:[ESI+4] 명령어는 GetProcAddress(778E0000, "MessageBoxA") API 를 호출하는 것입니다. 이 CALL 명령어를 실행하면 user32.MessageBoxA() API 시작 주소가 EAX 레지스터에 저장됩니다. (사용자 환경에 따라서 이 주소는 틀려집니다. 제 경우에는 EAX = 7793EA71 입니다.)


<Fig. 12>

(분량이 많아 다음 강좌에 이어서 하겠습니다.)

Trackback Address :: http://www.reversecore.com/trackback/87 관련글 쓰기



어셈블리(Assembly) 언어로 생성한 코드를 가지고 Injector 를 만들어 보도록 하겠습니다.

이전 강좌의 내용은 아래 링크를 참조하시기 바랍니다.




ThreadProc() 함수의 Binary 코드 얻기
지난 강좌에서 생성한 asmtest_patch.exe 파일을 OllyDbg 로 열어 보겠습니다. 우리가 프로그래밍한 ThreadProc() 의 주소는 401000 입니다. 메모리 윈도우에서 401000 주소로 갑니다.

 
<Fig. 1>

ThreadProc() 함수는 401000 ~ 401061 의 주소 영역입니다. 위 그림과 같이 이 영역을 선택하신 후 마우스 우측 메뉴의 "Copy - To file" 항목을 선택하시기 바랍니다. (아래 그림 참고)


<Fig. 2>

이렇게 저장한 파일을 텍스트 에디터로 열어보겠습니다. (GVIM 또는 AcroEdit 추천합니다.)


<Fig. 3>

위 텍스트 파일의 내용은 Hex 값으로 표현된 ThreadProc() 함수로써, IA-32 OpCode (Operation Code) 명령어 입니다. 이 내용은 곧 상대방 프로세스에 인젝션 시킬 코드가 되는 것입니다.

위 텍스트 파일을 아래와 같이 편집합니다. 불필요한 부분을 제거하고 모든 바이트마다 "0x" 표시를 붙여주고 ',' 로 연결합니다. 텍스트 에디터의 편집 기능(열 선택, 문자열 변경)을 적절히 사용하시면 편리합니다.


<Fig. 4>

위 그림에서 편집된 텍스트 내용을 보면 마치 C 언어의 BYTE 배열처럼 보이지 않습니까? 이게 바로 인젝션 시킬 코드 버퍼입니다. (아래 설명되는 CodeInjection2.cpp 파일에서 사용됩니다.)

편집된 텍스트 파일을 첨부합니다.



CodeInjection2.cpp
Injector 프로그램의 소스 코드입니다. 위에서 텍스트 에디터로 만든 코드 버퍼는 아래 소스에서 g_InjectionCode 배열에 사용되었습니다.

* 참고!
아래 소스코드는 MS Visual C++ 2008 Express Edition 에서 개발되었으며, Windows 7 32bit 환경에서 테스트 되었습니다. 또한 설명의 편의를 위하여 리턴 값 체크와 에러 처리 코드는 생략되었습니다. 원본 소스 코드는 위에 첨부된 CodeInjection2.cpp 파일을 참고하시기 바랍니다.

typedef struct _THREAD_PARAM 
{
    FARPROC pFunc[2];               // LoadLibraryA(), GetProcAddress()
} THREAD_PARAM, *PTHREAD_PARAM;

// ThreadProc()
BYTE g_InjectionCode[] = 
{
    0x55, 0x8B, 0xEC, 0x8B, 0x75, 0x08, 0x68, 0x6C, 0x6C, 0x00,
    0x00, 0x68, 0x33, 0x32, 0x2E, 0x64, 0x68, 0x75, 0x73, 0x65,
    0x72, 0x54, 0xFF, 0x16, 0x68, 0x6F, 0x78, 0x41, 0x00, 0x68,
    0x61, 0x67, 0x65, 0x42, 0x68, 0x4D, 0x65, 0x73, 0x73, 0x54,
    0x50, 0xFF, 0x56, 0x04, 0x6A, 0x00, 0xE8, 0x0C, 0x00, 0x00,
    0x00, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x43, 0x6F,
    0x72, 0x65, 0x00, 0xE8, 0x14, 0x00, 0x00, 0x00, 0x77, 0x77,
    0x77, 0x2E, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x63,
    0x6F, 0x72, 0x65, 0x2E, 0x63, 0x6F, 0x6D, 0x00, 0x6A, 0x00,
    0xFF, 0xD0, 0x33, 0xC0, 0x8B, 0xE5, 0x5D, 0xC3
};

/*
// ThreadProc()
004010ED    55               PUSH EBP
004010EE    8BEC             MOV EBP,ESP
004010F0    8B75 08          MOV ESI,DWORD PTR SS:[EBP+8] 
004010F3    68 6C6C0000      PUSH 6C6C                      
004010F8    68 33322E64      PUSH 642E3233
004010FD    68 75736572      PUSH 72657375
00401102    54               PUSH ESP                       
00401103    FF16             CALL DWORD PTR DS:[ESI] 
00401105    68 6F784100      PUSH 41786F
0040110A    68 61676542      PUSH 42656761
0040110F    68 4D657373      PUSH 7373654D
00401114    54               PUSH ESP                      
00401115    50               PUSH EAX                      
00401116    FF56 04          CALL DWORD PTR DS:[ESI+4]   
00401119    6A 00            PUSH 0                        
0040111B    E8 0C000000      CALL 0040112C
00401120    <ASCII>                                         
0040112C    E8 14000000      CALL 00401145
00401131    <ASCII>                                         
00401145    6A 00            PUSH 0                         
00401147    FFD0             CALL EAX                       
00401149    33C0             XOR EAX,EAX                        
0040114B    8BE5             MOV ESP,EBP
0040114D    5D               POP EBP                            
0040114E    C3               RETN
*/

BOOL InjectCode(DWORD dwPID)
{
    HMODULE         hMod            = NULL;
    THREAD_PARAM    param           = {0,};
    HANDLE          hProcess        = NULL;
    HANDLE          hThread         = NULL;
    LPVOID          pRemoteBuf[2]   = {0,};

    hMod = GetModuleHandleA("kernel32.dll");

    // set THREAD_PARAM
    param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA");
    param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress");

    // Open Process
    hProcess = OpenProcess(PROCESS_ALL_ACCESS,    
                           FALSE,                     
                           dwPID);                    

    // Allocation for THREAD_PARAM
    pRemoteBuf[0] = VirtualAllocEx(hProcess,       
                                   NULL,               
                                   sizeof(THREAD_PARAM), 
                                   MEM_COMMIT,            
                                   PAGE_READWRITE);       

    WriteProcessMemory(hProcess,                      
                       pRemoteBuf[0],                  
                       (LPVOID)&param,                 
                       sizeof(THREAD_PARAM),          
                       NULL);                           

    // Allocation for g_InjectionCode
    pRemoteBuf[1] = VirtualAllocEx(hProcess,           
                                   NULL,                   
                                   sizeof(g_InjectionCode), 
                                   MEM_COMMIT,              
                                   PAGE_EXECUTE_READWRITE); 

    WriteProcessMemory(hProcess,                        
                       pRemoteBuf[1],                     
                       (LPVOID)&g_InjectionCode,         
                       sizeof(g_InjectionCode),          
                       NULL);                             

    hThread = CreateRemoteThread(hProcess,             
                                 NULL,                    
                                 0,                       
                                 (LPTHREAD_START_ROUTINE)pRemoteBuf[1], 
                                 pRemoteBuf[0],          
                                 0,                       
                                 NULL);                   

    WaitForSingleObject(hThread, INFINITE);

    CloseHandle(hThread);
    CloseHandle(hProcess);

    return TRUE;
}

<코드 1>

위의 코드와 지난번 CodeInjection.cpp 의 코드와의 가장 큰 차이점은 인젝션 시키는 코드 내에 필요한 문자열 데이터를 같이 포함시킨 것입니다. 

따라서 _THREAD_PARAM 구조체에서 문자열 멤버가 사라졌습니다. 그리고 기존 C로 된 ThreadProc() 함수 대신 <Fig. 4> 의 OpCode 버퍼(g_InjectionCode)가 사용됩니다. (이 OpCode 버퍼를 생성하기 위해 OllyDbg 의 “Assembly” 명령을 사용했던 것을 기억하시죠?)

조금 더 정교하게 프로그래밍을 했다면 _THREAD_PARAM 구조체조차 필요 없도록 만들 수도 있습니다. 세부적인 구현 방법은 어디까지나 구현하는 사람의 마음입니다. 

중요한 것은 어셈블리 프로그래밍을 통해서 생성된 OpCode 버퍼를 Injector 소스코드에 사용하여 상대방 프로세스에 인젝션 시킨다는 것입니다.

예전에 설명 드린 CodeInjection.cpp 소스 코드와 비교해서 보시면 차이점을 더 명확히 이해할 수 있을 것입니다. (위 <코드 1> 의 세부 설명은 생략합니다. Code Injection 의 구현 방법에 대해서는 밑의 링크된 설명을 참고하시기 바랍니다.)



다음 강좌에서 실제로 상대방 프로세스에 인젝션 시킨 후 디버깅을 하면서 저 어셈블리 코드가 어떤 의미를 가지고 있는지 알아보도록 하겠습니다.

☞ 어셈블리 언어를 이용한 Code Injection (4)


ReverseCore

위 글이 도움이 되셨다면 추천(VIEW ON) 부탁 드려요~

Trackback Address :: http://www.reversecore.com/trackback/86 관련글 쓰기

  1. 지나가던이 2010/07/03 08:01 댓글주소 | 수정 | 삭제 | 댓글

    좋은 글 감사합니다. 항상 잘 배우고 있습니다.
    전 그동안은 코드 인젝션 할땐 DLL 인젝션과 병행 해서, 인젝션 코드에서 DLL의 함수를 call 하도록 간단하게 만들었었는데, 이렇게 함수 코드를 직접 집어넣는 방법도 괜찮네요.

    • reversecore 2010/07/03 14:56 댓글주소 | 수정 | 삭제

      네, 상황에 맞게 적절히 선택해서 사용하시면 되는데요.
      보통은 DLL Injection 이 많이 쓰입니다.

      Code Injection 을 소개하는 이유는 리버싱에 대해 좀 더 깊이있는 공부를 해보자는 뜻입니다.

      감사합니다.



지난 강좌에 이어지는 내용입니다. 

어셈블리 언어를 이용한 Code Injection (1)




ThreadProc() 


Assembly 언어로 ThreadProc() 함수를 만들겠습니다. 지난 강좌에서 C 로 만든 ThreadProc() 과의 차이점은 Code 사이에 필요한 Data(문자열)를 포함 시키는 것입니다.

각자 아래 그림과 같이 입력해 주시기 바랍니다. 각 Assembly 명령어에 대한 설명은 뒤쪽에서 하겠습니다. (“Fill with NOP’s” 옵션은 uncheck 해주시고, 오타가 나면 그 주소에 가서 다시 입력하시면 됩니다.) 


<Fig. 5>

40102E 주소의 CALL 0040103F 명령어까지 잘 입력하셨나요? 그 다음에는 문자열을 입력합니다. Assemble 윈도우를 닫아주세요. OllyDbg의 코드 윈도우에서 401033 주소에 커서를 위치시킨 후 아래 그림과 같이 "Edit" 명령(단축키 : [Ctrl+E])을 내려줍니다.


<Fig. 6>

위 그림의 Edit 윈도우에서 "ASCII" 항목에 "ReverseCore" 를 입력합니다. 문자열은 반드시 NULL 로 끝나야 하므로 "HEX" 항목에서 00 값을 추가해 줍니다. ("Keep size" 옵션은 uncheck 로 해주세요.)

이와 같이 입력한 후 OllyDbg 에서 코드를 보면 아래 그림과 같습니다.


<Fig. 7>

위 그림에서 푸른색으로 반전된 영역이 바로 "ReverseCore" 문자열 영역입니다. 매우 이상한 명령어로 표시된 것을 볼 수 있습니다. 이렇게 표시되는 이유는 OllyDbg 의 Disassembler 가 문자열을 IA-32 명령어로 잘 못 해석한 것입니다. 이것은 어디까지나 Code 위치에 문자열을 입력한 저의 잘못(?)이지 OllyDbg 의 Disassembler 의 문제는 아닙니다.

* 참고
디버깅을 할 때 이와 같은 상황을 종종 부딪히게 됩니다. 또한 이를 이용한 Anti-Debugging 기법도 있습니다. 향후 Anti-Debugging 에 대해서 설명할 때 소개해 드리겠습니다.

위 <Fig. 7> 화면처럼 문자열을 선택한 상태에서 "Analysis" 명령(단축키 : Ctrl+A)을 내려보겠습니다. 

* 참고
OllyDbg 의 “Analysis” 명령은 코드를 다시 해석하라는 명령입니다. 주로 Unpack 된 코드를 재 해석할 때 많이 사용하게 됩니다.


<Fig. 8>

위 그림은 Analysis 명령이 수행된 이후에 코드의 모습입니다. 401033 주소의 "ReverseCore" 문자열은 잘 보입니다만, 401000 주소 이후의 명령어들은 잘 못 해석이 되었습니다. (OllyDbg 2.0 에서도 코드와 데이터를 100% 정확히 구별해서 보여주지는 못합니다. 사실 이게 문자열인지 명령어인지 판단하기 어렵습니다.)

위 <Fig. 8> 은 코드를 보기 어려우므로 마우스 우측 메뉴의 "Analysis – Remove analysis from module" 명령을 사용하여 코드를 원래대로 되돌립니다.


<Fig. 9>

위 Remove analysis 명령을 사용하면 다시 위의 <Fig. 7> 과 같은 형태의 코드로 보이게 됩니다.

이제 401033 주소의 "ReverseCore" 문자열 뒤의 40103F 주소부터 다시 입력할 차례입니다. (<Fig. 7>, <Fig. 8> 의 40102E 주소의 CALL 40103F 명령어 참고)


<Fig. 10>

그리고 401044 주소에 문자열("www.reversecore.com")을 입력합니다. (마지막에 NULL 입력을 잊지 마시구요.)


<Fig. 11>

401058 주소부터 아래와 같이 명령어를 입력합니다.


<Fig. 12>

이것으로써 ThreadProc() 코드 입력이 모두 완료되었습니다. 아래 그림에 전체 코드가 나타나 있으니 각자 오타를 점검해보시기 바랍니다.
 

<Fig. 13>

* 참고
401033, 401044 주소의 내용은 명령어가 아니고 문자열입니다. OllyDbg 에서 문자열을 명령어로 인식하여 이상하게 표시하고 있습니다.



Save File


위에서 생성한 코드를 잘 저장합니다. OllyDbg 의 코드 윈도우에서 마우스 우측 버튼 메뉴 중 "Copy to executable \ All modifications" 를 선택합니다. (아래 그림 참고)


<Fig. 14>

아래 그림과 같이 확인 메시지 창이 뜹니다. "Copy all" 을 선택해 주세요.


<Fig. 15>

마지막으로 변경 내용을 보여주는 창이 나타납니다. 마우스 우측 메뉴의 "Save file" 항목을 선택합니다. (아래 그림 참고)


<Fig. 16>

이후에 나타나는 파일 저장 다이알로그에서 적당한 파일 이름(asmtest_patch.exe)을 적어준 후 저장합니다. 

다음 강좌에서 asmtest_patch.exe 의 어셈블리 코드를 이용해서 Injector 를 만들어 보도록 하겠습니다.


* 참고 : 새롭게 소개된 OllyDbg 명령어

Assemble [Space]
Analysis [Ctrl+A]
New origin here [Ctrl+Gray *]


ReverseCore

위 글이 도움이 되셨다면 추천(VIEW ON) 부탁 드려요~

Trackback Address :: http://www.reversecore.com/trackback/85 관련글 쓰기

  1. badcob 2010/07/18 01:27 댓글주소 | 수정 | 삭제 | 댓글

    이런 보석같은 글에 리플이 없는게 아쉬워서 몇글자 적어봅니다;
    해외 문서들을 보면서 궁금하고 또 상세한 설명이 아쉬웠던 부분들이
    이 블로그에 있는 글들로 정말 많이 채워지는 기분이 드네요.
    오늘도 잘 보고 물러갑니다. ( __)



어셈블리(Assembly) 프로그래밍 언어를 이용하여 Code Injection 기법에 사용되는 코드를 생성해 보도록 하겠습니다. 


Code Injection 관련 내용은 아래 강좌를 참고하시기 바랍니다.




Goal


이번 강좌에서는 OllyDbg 의 Assemble 기능을 이용하여 Assembly 언어로 인젝션 시킬 코드(ThreadProc() 함수)를 만들어 보도록 하겠습니다. Assembly 언어는 C 언어보다 훨씬 더 자유로운 (정형화 되지 않은) 코드를 생성할 수 있습니다. (예: 스택(Stack), 레지스터(Register) 를 직접 access 가능) 그리고 CodeInjection.cpp 소스코드를 수정하여 Assembly 언어로 제작된 ThreadProc() 함수를 notepad.exe 프로세스에 인젝션 시켜보도록 하겠습니다. 

이전 강좌에서 설명 드린 (C 언어로 생성된) ThreadProc() 과 어떤 차이점이 있는지 잘 살펴보시기 바랍니다.



Assembly 프로그래밍


C/C++ 언어의 대표적인 개발 툴은 MicroSoft Visual C++Borland C++ Builder 입니다. 

Assembly 언어에도 MASM(MicroSoft Macro Assembler), TASM(Borland Turbo Assembler), FASM(Flat Assembler) 등의 개발 툴(Assembler)이 있습니다. 

참고로 저는 C/C++ 언어는 MS Visual C++ 로 개발하고 Assembly 언어는 MASM 으로 개발합니다. 특히 MASM 은 다양한 Macro 함수와 라이브러리를 지원하기 때문에 거의 C 언어와 비슷한 수준으로 편리하게 프로그래밍을 할 수 있습니다.

Assembly 프로그래밍을 정식으로 하시려면 MASM 을 설치하고 프로그래밍 하시면 됩니다. 또는 Visual C++ 와 같은 C 언어 개발 툴에서 인라인 어셈블리(Inline Assembly)를 사용할 수 도 있습니다. 이런 방식은 개발자에게 잘 어울리는 방식입니다.

우리는 모두 리버서(Reverser)이기 때문에 이번 강좌에서는 리버서에게 좀 더 잘 어울리는 방법을 소개하겠습니다. 바로 OllyDbg 에서 지원하는 "Assemble" 기능을 이용해서 프로그래밍을 하는 것입니다. 

* 참고
OllyDbg 의 "Assemble" 기능은 간단한 Assembly 프로그래밍을 지원하는데, 이는 리버싱에 매우 유용하게 사용됩니다. (디버깅하면서 코드를 이리저리 수정할 일이 많기 때문이지요.)



OllyDbg 의 "Assemble" 명령


OllyDbg 의 “Assemble” 명령어를 이용하여 Assembly 프로그래밍을 해보겠습니다.

위에 첨부된 asmtest.exe 실행 파일을 OllyDbg 로 열어보겠습니다. (asmtest.exe 는 Assembly 프로그래밍 테스트 용도로 제작된 -아무런 기능이 없는- 실행 파일입니다.)

 
<Fig. 1>

위 그림과 같이 코드 섹션의 맨 윗부분(401000)을 봐주시기 바랍니다. OllyDbg 의 새로운 명령어를 소개해 드리겠습니다. 바로 EIP 를 원하는 주소로 바꿔버리는 기능입니다. 

OllyDbg 의 코드 윈도우에서 401000 주소에 커서를 위치시킨 후 마우스 우측 메뉴의 "New origin here [Ctrl+Gray*]" 항목을 선택해 주세요.


<Fig. 2>

아래 그림과 같이 EIP는 401000 주소로 변하게 됩니다.


<Fig. 3>

위 EIP 변경 기능은 디버깅에 유용하게 사용될 수 있으므로 잘 기억해 두시기 바랍니다.

* 참고!
"New origin here" 기능은 단순히 EIP 만 바꿔버리는 것이기 때문에 직접 디버깅을 해서 그 주소로 가는 것과는 틀립니다. 레지스터와 스택의 내용은 전혀 바뀌지 않기 때문입니다.

이제 401000 주소에서 "Assemble" 명령(단축키 : [Space])을 내리면 아래 그림과 같은 Assemble 입력 창이 나타납니다.


<Fig. 4>

이제부터 OllyDbg 에서 간단한 Assembly 프로그래밍을 할 수 있게 되었습니다.

* 참고
위 <Fig. 4> 에서 "Fill with NOP’s" 항목은 uncheck 해주시기 바랍니다. OllyDbg 의 Assemble 명령은 해당 주소에 사용자 코드를 입력하는 것입니다. 만약 이 항목이 check 되어 있으면 기존의 코드 보다 짧은 길이의 코드를 입력했을 때 남은 길이만큼 NOP (No Operation) 명령어를 채워 넣어서 전체적인 Code Alignment 를 맞춰주게 됩니다. 이번 강좌에서는 설명의 편의를 위해서 uncheck 상태로 진행하도록 하겠습니다.


(내용이 많아 다음 강좌에 이어서 하겠습니다.)



Trackback Address :: http://www.reversecore.com/trackback/84 관련글 쓰기


Code Injection 기법 (3)

study 2010/06/24 10:43

Code Injection 기법에 의해서 인젝션된 코드를 디버깅 하는 방법에 대해서 알아보도록 하겠습니다. 

이전 강좌의 내용은 아래 링크를 참조하시기 바랍니다.




Code Injection 디버깅 실습
1. notepad.exe 디버깅

OllyDbg 를 이용하여 notepad.exe 파일의 디버깅을 시작합니다. 아래 그림과 같이 실행[F9] 버튼을 선택해서 notepad.exe 를 "Running" 상태로 만들어주세요.


<Fig. 1>

2. OllyDbg 옵션 변경

Code Injection 은 상대방 프로세스에 새로운 스레드를 생성하는 기법이므로 아래와 같이 OllyDbg 의 옵션을 변경하면 인젝션된 스레드 코드 시작부터 디버깅이 가능합니다.


<Fig. 2>

이제부터 notepad.exe 프로세스에서 스레드가 생성된다면 해당 스레드 함수 시작코드에서 멈추게 됩니다.

3. CodeInjection.exe 실행

Process Explorer 를 이용하여 notepad.exe 프로세스의 PID 를 구합니다.


<Fig. 3>

PID 값을 실행 파라미터로 하여 CodeInjection.exe 를 실행합니다.

 
<Fig. 4>

4. 스레드 시작 코드

CodeInjection.exe 프로세스가 실행되어 코드 인젝션이 성공하면 아래 그림과 같이 인젝션된 스레드 코드 시작 위치에서 디버깅이 멈추게 됩니다.


<Fig. 5>

주의 하실점은 디버깅이 멈춘 것이지 EIP 가 이곳으로 세팅된 것이 아닙니다.

위 그림의 150000 주소에 BP 를 설치한 후 실행[F9] 시켜 주세요. 실행 제어가 정확히 BP 설치 주소(150000)에 멈추게 되고 이제부터 펀안하게 디버깅을 진행하시면 됩니다.

* 참고!
실행 환경에 따라서 위 주소는 다르게 표시될 수 있습니다.

OllyDbg 의 편리한 기능을 이용하여 인젝션된 코드를 디버깅 하는 방법에 대해서 살펴보았습니다.

다음 강좌에는 C 언어가 아닌 Assembly 언어를 이용해서 인젝션 코드를 만들어 보도록 하겠습니다. 많이 기대해 주세요~

☞ 어셈블리 언어를 이용한 Code Injection (1)

ReverseCore

위 글이 도움이 되셨다면 추천(VIEW ON) 부탁 드려요~

Trackback Address :: http://www.reversecore.com/trackback/83 관련글 쓰기

  1. Acid 2010/06/24 11:18 댓글주소 | 수정 | 삭제 | 댓글

    1등 ^^
    며칠전에 우연히 이 사이트에 들어왔다가 지금까지 궁금했던 것들 한꺼번에 배우고 있습니다.
    앞으로도 좋은글 부탁드려요~

  2. 궁금 2011/06/02 15:44 댓글주소 | 수정 | 삭제 | 댓글

    windows 7에서는 "The token dows not have the specified privilege" 에러가 납니다
    특별한 이유가 있을까요?

    그래서 cmd.exe를 관리자로 실행하고 codeInjectio.exe 실행했더니 잘 됩니다
    관리자로 실행하지 않으면 코드인젝션은 되지 않는건가요?

    • reversecore 2011/06/03 21:08 댓글주소 | 수정 | 삭제

      안녕하세요.

      네, 말씀하신대로 Vista, 7 에서는 그러한 에러가 자주 발생합니다. XP 보다 보안성이 강화되었기 때문입니다.

      시스템 프로세스가 아닌 같은 유저 환경에서 실행한 프로세스에는 인젝션이 가능합니다.

      감사합니다.

  3. Andi 2011/08/09 10:00 댓글주소 | 수정 | 삭제 | 댓글

    좋은 정보 감사합니다.

  4. 디버거 2011/10/12 19:26 댓글주소 | 수정 | 삭제 | 댓글

    어느덧 Code Injection까지 무작정 따라 왔는데요.

    실습용 CodeInjection.exe로는 잘 되는데
    컴파일 해서 실행하면 에러가 나면서 notepad가 꺼집니다.

    환경은 Winxp SP3, VS6.0입니다.

    cpp파일을 그대로 컴파일 하고 좀 따라가보다 나니
    dwSize = (DWORD)InjectCode - (DWORD)ThreadProc;
    에서 dwSize가 5가 되는데 이것이 맞는건지 가르쳐주세요.

    • reversecore 2011/10/28 01:17 댓글주소 | 수정 | 삭제

      안녕하세요.

      dwSize 는 최소 ThreadProc() 함수 크기 이상으로 나와야 합니다. 아마 Debug 모드로 빌드 하신 것 같습니다. Release 모드로 빌드 해보시기 바랍니다.

      감사합니다.


Code Injection 기법 (2)

study 2010/06/23 00:15

Code Injection 실습 예제인 CodeInjection.exe 의 소스 코드(CodeInjection.cpp)를 살펴보도록 하겠습니다. 


이전 강좌의 내용은 아래 링크를 참조하시기 바랍니다.

Code Injection 기법 (1)



CodeInjection.cpp

* 참고!
CodeInjection.cpp 는 Visual C++ 2008 Express Edition 으로 개발되었으며 Windows 7 32bit 환경에서 테스트 되었습니다. 또한 Visual C++ 의 코드 최적화 기능을 사용하지 않고 빌드 하였습니다. (/Od) 

아래 소개되는 코드들은 설명의 편의를 위하여 에러 처리 부분을 생략하였습니다. 완전한 코드는 첨부된 CodeInjection.cpp 파일을 참고하시기 바랍니다.

main()

먼저 main() 함수를 살펴 보겠습니다.

int main(int argc, char *argv[])
{
    DWORD dwPID     = 0;

    if( argc != 2 )
    {
        printf("\n USAGE  : %s <pid>\n", argv[0]);
        return 1;
    }

    // code injection
    dwPID = (DWORD)atol(argv[1]);
    InjectCode(dwPID);

    return 0;
}

<코드 1 – main() 함수>

main() 함수의 역할은 InjectCode() 함수를 호출하는 것입니다. 이때 함수 파라미터로 상대방 프로세스의 PID 값을 넘겨줍니다.

ThreadProc()

이제 상대방 프로세스에 인젝션 시킬 코드(스레드 함수)를 살펴보겠습니다.

// Thread Parameter
typedef struct _THREAD_PARAM 
{
    FARPROC pFunc[2];               // LoadLibraryA(), GetProcAddress()
    char    szBuf[4][128];          // "user32.dll", "MessageBoxA", 
                                    // "www.reversecore.com", "ReverseCore"
} THREAD_PARAM, *PTHREAD_PARAM;

// LoadLibraryA()
typedef HMODULE (WINAPI *PFLOADLIBRARYA)
(
    LPCSTR lpLibFileName
);

// GetProcAddress()
typedef FARPROC (WINAPI *PFGETPROCADDRESS)
(
    HMODULE hModule,
    LPCSTR lpProcName
);

// MessageBoxA()
typedef int (WINAPI *PFMESSAGEBOXA)
(
    HWND hWnd,
    LPCSTR lpText,
    LPCSTR lpCaption,
    UINT uType
);

// Thread Procedure
DWORD WINAPI ThreadProc(LPVOID lParam)
{
    PTHREAD_PARAM   pParam      = (PTHREAD_PARAM)lParam;
    HMODULE         hMod        = NULL;
    FARPROC         pFunc       = NULL;

    // LoadLibrary(“user32.dll”)
    //   pParam->pFunc[0] = kernel32!LoadLibraryA()
    //   pParam->szBuf[0] = “user32.dll”
    hMod = ((PFLOADLIBRARYA)pParam->pFunc[0])(pParam->szBuf[0]);

    // GetProcAddress(“MessageBoxA”)
    //   pParam->pFunc[1] = kernel32!GetProcAddress()
    //   pParam->szBuf[1] = “MessageBoxA”
    pFunc = (FARPROC)((PFGETPROCADDRESS)pParam->pFunc[1])(hMod, pParam->szBuf[1]);

    // MessageBoxA(NULL, “www.reversecore.com”, “ReverseCore”, MB_OK)
    //   pParam->pFunc[1] = kernel32!GetProcAddress()
    //   pParam->szBuf[1] = “MessageBoxA”
    ((PFMESSAGEBOXA)pFunc)(NULL, pParam->szBuf[2], pParam->szBuf[3], MB_OK);

    return 0;
}

<코드 2 – ThreadProc() 함수>

위 코드에서 실제로 인젝션 되는 부분은 ThreadProc() 함수입니다. 그 위의 typedef 문은 C 언어 문법을 위한 것이므로 인젝션 시킬 필요가 없습니다.

ThreadProc() 의 코드는 함수 포인터를 많이 사용해서 얼핏 복잡하게 보이지만 사실 내용은 아래와 같이 간단합니다.

hMod = LoadLibraryA(“user32.dll”);
pFunc = GetProcAddress(hMod, “MessageBoxA”);
pFunc(“www.reversecore.com”, “ReverseCore”);

<코드 2> 의 주석을 참조하시면 ThreadProc() 의 코드는 쉽게 이해가 가실 것입니다.

중요한 것은 ThreadProc() 코드의 개념입니다. 

Code Injection 기법의 핵심은 독립 실행 코드를 인젝션 시키는 것입니다. 

그러기 위해서 코드와 (코드에서 참조하는) 데이터를 같이 인젝션 시키는 것입니다. 그리고 인젝션 시키는 코드에서 역시 인젝션 시킨 데이터를 정확히 참조할 수 있도록 해야 합니다.

위 ThreadProc() 함수를 보시면 직접 API 를 호출 하지 않습니다. 또한 문자열도 직접 정의해서 사용하지 않습니다. 전부 스레드 파라미터로 넘어온 THREAD_PARAM 구조체에서 가져다 사용하고 있습니다.

만약 일반적인 프로그램이라면 ThreadProc() 의 코드는 아래와 같이 간단히 작성할 수 있습니다.

DWORD WINAPI ThreadProc(LPVOID lParam)
{
    MessageBoxA(NULL, "www.reversecore.com", "ReverseCore", MB_OK);

    return 0;
}

<코드 3 – 일반적인 프로그램에서의 ThreadProc()>

위 <코드 3>을 빌드하여 생성된 파일을 디버거로 보면 아래 그림과 같습니다.

 
<Fig. 1>

위 그림의 코드(10001000 ~ 10001018 영역)를 다른 프로세스에 그대로 인젝션 시킨다면 정상적으로 실행되지 않습니다. 그 이유는 코드에서 사용되는 10009290, 1000929C, 100080F0 주소의 내용이 상대방 프로세스에는 없기 때문입니다.

따라서 저 주소에 해당하는 문자열과 API 주소를 같이 인젝션 시켜야 합니다. 또한 <Fig. 1>의 코드 역시 그 인젝션된 데이터의 주소를 정확히 참조하도록 프로그래밍 되어야 합니다.

이와 같은 조건을 만족시키기 위해서 <코드 2> 의 ThreadProc() 함수는 THREAD_PARAM 구조체를 이용해서 2 개의 API 주소와 4 개의 문자열 데이터를 받아들입니다. 2 개의 API 는 바로 “LoadLibraryA()”“GetProcAddress()” 입니다. 이 2 개의 API 만 있으면 모든 라이브러리의 함수를 호출 할 수 있습니다. 

* 참고 사항

1. 위 실습 예제의 경우에 LoadLibraryA() 와 GetProcAddress() 의 주소 말고 MessageBoxA() 의 주소를 직접 전달하여 사용해도 됩니다. 하지만 정석은 LoadLibraryA() 와 GetProcAddress() 만을 전달한 후 이를 이용해서 필요한 DLL 을 로딩시켜 원하는 함수 주소를 직접 구하는 것입니다. 이 방식의 장점은 해당 라이브러리를 프로세스에 정확히 로딩시킨다는 것입니다. 가령 notepad.exe 프로세스에 윈도우 소켓 API 인 ws2_32!connect() 의 주소를 넘겨주면 에러가 발생할 것입니다. (notepad.exe 에 기본적으로 ws2_32.dll 이 로딩되지 않았으니까요.)

2. 대부분의 유저 모드 프로세스는 kernel32.dll 을 로딩하므로 LoadLibraryA(), GetProcAddress() 의 주소를 직접 넘기는 것은 크게 무리가 없습니다. 단, kernel32.dll 을 로딩하지 않는 시스템 프로세스(예: smss.exe)도 있으니 사전에 꼭 확인하시기 바랍니다.

3. Kernel32.dll 같은 시스템 라이브러리는 OS 가 부팅되어 있는 상태에서는 모든 프로세스에서 동일한 주소에 로딩되어 있습니다. OS 버전이 틀리거나 재부팅(Vista, 7 의 경우)을 하거나 하면 같은 모듈이라도 로딩 주소는 틀려집니다.

위 <코드 2> 의 내용을 디버거로 살펴보면 아래 그림과 같습니다.

 
<Fig. 2>

위의 <Fig. 2> 의 코드를 보시면 모든 중요한 데이터는 스레드 파라미터인 pParam 으로 받아서 사용하는 것을 알 수 있습니다. 즉, <Fig. 2> 의 ThreadProc() 함수는 독립 실행 코드라고 말 할 수 있습니다. 위의 <Fig. 2> 와 앞에서 소개한 <Fig. 1> 를 비교해 보시면 그 차이점을 확인하실 수 있습니다.

* 참고!
Visual C++ 2008 Express Edition 에서 프로젝트의 [Release/Debug] 모드와 [최적화] 옵션에 따라서 CodeInjection.cpp 파일은 <Fig. 2> 와는 다른 형태로 빌드 될 수 있습니다. 위 실습 예제는 Release 모드에서 최적화 옵션 사용 안함(/Od)으로 빌드 하였습니다. 

InjectCode()

아래는 Code Injection 기법의 핵심인 InjectCode() 함수입니다.

BOOL InjectCode(DWORD dwPID)
{
    HMODULE         hMod            = NULL;
    THREAD_PARAM    param           = {0,};
    HANDLE          hProcess        = NULL;
    HANDLE          hThread         = NULL;
    LPVOID          pRemoteBuf[2]   = {0,};
    DWORD           dwSize          = 0;

    hMod = GetModuleHandleA("kernel32.dll");

    // set THREAD_PARAM
    param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA");
    param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress");
    strcpy_s(param.szBuf[0], "user32.dll");
    strcpy_s(param.szBuf[1], "MessageBoxA");
    strcpy_s(param.szBuf[2], "www.reversecore.com");
    strcpy_s(param.szBuf[3], "ReverseCore");

    // Open Process
    hProcess = OpenProcess(PROCESS_ALL_ACCESS,  // dwDesiredAccess
                           FALSE,                   // bInheritHandle
                           dwPID);                  // dwProcessId

    // Allocation for THREAD_PARAM
    dwSize = sizeof(THREAD_PARAM);
    pRemoteBuf[0] = VirtualAllocEx(hProcess,        // hProcess
                                   NULL,            // lpAddress
                                   dwSize,          // dwSize
                                   MEM_COMMIT,      // flAllocationType
                                   PAGE_READWRITE); // flProtect

    WriteProcessMemory(hProcess,                    // hProcess
                       pRemoteBuf[0],               // lpBaseAddress
                       (LPVOID)&param,              // lpBuffer
                       dwSize,                      // nSize
                       NULL);                       // [out] lpNumberOfBytesWritten

    // Allocation for ThreadProc()
    dwSize = (DWORD)InjectCode - (DWORD)ThreadProc;
    pRemoteBuf[1] = VirtualAllocEx(hProcess,        // hProcess
                                   NULL,            // lpAddress
                                   dwSize,          // dwSize
                                   MEM_COMMIT,      // flAllocationType
                                   PAGE_EXECUTE_READWRITE); // flProtect

    WriteProcessMemory(hProcess,                    // hProcess
                       pRemoteBuf[1],               // lpBaseAddress
                       (LPVOID)ThreadProc,          // lpBuffer
                       dwSize,                      // nSize
                       NULL);                       // [out] lpNumberOfBytesWritten

    hThread = CreateRemoteThread(hProcess,          // hProcess
                                 NULL,              // lpThreadAttributes
                                 0,                 // dwStackSize
                                 (LPTHREAD_START_ROUTINE)pRemoteBuf[1],
                                 pRemoteBuf[0],     // lpParameter
                                 0,                 // dwCreationFlags
                                 NULL);             // lpThreadId

    WaitForSingleObject(hThread, INFINITE);

    CloseHandle(hThread);
    CloseHandle(hProcess);

    return TRUE;
}

<코드 4 - InjectCode() 함수>

위 코드는 DLL Injection 코드와 매우 유사합니다. 

InjectCode() 함수의 앞 부분은 THREAD_PARAM 구조체 변수를 세팅하고 있습니다. 이 값들은 상대방 프로세스에 인젝션 되어 ThreadProc() 스레드 함수에 파라미터로 전달될 것입니다.

* 참고!
Windows 7 에서 모든 프로세스에 로딩된 kernel32.dll 의 주소가 동일하므로 CodeInjection.exe 프로세스에서 구한 API(“LoadLibraryA”, “GetProcAddress”) 주소와 notepad.exe 프로세스에서 구한 API(“LoadLibraryA”, “GetProcAddress”) 주소가 서로 동일하다는 것을 기억하시기 바랍니다.

그리고 API 함수 호출이 이어지는데요, 핵심 API 함수들의 호출 흐름만 살펴보면 아래와 같습니다.

OpenProcess()

// data : THREAD_PARAM
VirtualAllocEx()
WriteProcessMemory()

// code : ThreadProc()
VirtualAllocEx()
WriteProcessMemory()

CreateRemoteThread()

위 코드의 핵심은 상대방 프로세스에 data 와 code 를 각각 메모리 할당하고 인젝션 시켜 준다는 것입니다. 

마지막으로 CreateRemoteThread() API 를 이용해서 원격 스레드를 실행시킵니다.

+---+

이로써 Code Injection 기법을 이용한 실습 예제 소스코드에 대한 설명을 마치도록 하겠습니다.

설명의 편의성을 위하여 매우 기초적인 실습 예제를 소개하였습니다. Code Injection 의 개념을 이해하시는데 어려움이 없을 거라 생각됩니다. 위 개념을 이해하셨다면 다양한 아이디어로 자신만의 Code Injection 기법을 연습해 보시기 바랍니다

* 참고!
제가 Code Injection 기법을 구현할 때 인젝션 시킬 코드 부분은 어셈블리 언어로 프로그래밍 합니다. 복잡한 것은 MASM 을 사용하고, 간단한 것은 OllyDbg 의 “Assemble” 명령을 사용합니다. (단축키 [Space]) 이렇게 만들어진 Hex 코드 버퍼를 위 InjectCode() 함수 내에서 상대방 프로세스에 인젝션 시켜줍니다. 이러한 방법은 좀 더 직관적인 인젝션 코드를 만드는데 도움이 됩니다. Code Injection 마지막 강좌에서 간단히 실습해보도록 하겠습니다.

다음 강좌에서는 Code Injection 기법을 디버깅 하는 방법에 대해서 알아보도록 하겠습니다.


ReverseCore

위 글이 도움이 되셨다면 추천(VIEW ON) 부탁 드려요~

Trackback Address :: http://www.reversecore.com/trackback/82 관련글 쓰기

  1. Ezbeat 2010/06/23 06:58 댓글주소 | 수정 | 삭제 | 댓글

    와아~ 축구도 16강 진출해서 기쁜 마음에 들어와봤는데.. 글이 올라와서 있어서 더욱 기쁘네요!
    역시나 좋은 강좌 잘 봤습니다.

    제가 코드 인젝션을 응용해서 프로그램을 하나 만들어 볼건데.. 인젝션 시킬 Thread에서 API함수가 아닌 일반 함수(직접 만든 함수)를 사용해보려고 합니다.
    막상 구현해보려니.. 상당히 난해하군요..ㅠㅠ
    1. Thread에서 사용할 함수의 내부에서 사용된 모든 API함수 또한 넘겨진 구조체에 있는 값을 사용해야한다.
    2. 해당 함수도 인젝션을 시키고 들어간 주소를 구조체에 담아야한다..;;
    대충 이렇게 구현해야할 꺼같은데.. Code Injection을 사용해 API후킹을 한다면..-_-;;
    구현하는데 쫌 시간이 걸리겠군요..ㅠㅠ

    아 맞다.. 7월 5일날 입대(합격!)를 해야하는데 -_-;; 강좌를 다보고갈 수 있겠죠?? 하핫;;

    • reversecore 2010/06/23 21:18 댓글주소 | 수정 | 삭제

      원리는 동일하기 때문에 알고 계신 내용을 곰곰히 생각해 보시면 충분히 해결하실 수 있으실 겁니다.

      Code Injection 기법 설명이 끝나면 바로 이어서 Code Injection 을 이용한 API Hooking 에 대한 강좌를 진행할 예정입니다.

      원하시는 바를 꼭 이루시기 바랍니다.

      감사합니다.

  2. 궁금합니다.. 2011/01/01 21:01 댓글주소 | 수정 | 삭제 | 댓글

    궁금한게 있는데요!!

    컴파일을 하고나서 하면 CreateRemoteThread() fail : err_code = 5

    이렇게 뜨는데요.

    Error Lookup에서 찾아보니. 엑새스가 거부 되었습니다. 라고 나오는데

    어떻게 해야되나요 ? 관리자 권한으로도 실행해 보앗는데.. 안되네요!

    • reversecore 2011/01/03 01:03 댓글주소 | 수정 | 삭제

      안녕하세요.

      이전 글에 소개된 CodeInjection.exe 를 사용해도 제대로 동작하지 않는지요? (http://www.reversecore.com/attachment/cfile21.uf@20491A014C1F87C766AA91.exe)

      에러 메시지만 보면 권한이 없는것 같은데요. 위에 첨부된 CodeInjection.zip 코드 그대로 하신것 맞으시죠? 블로그 본문에 있는 코드는 실제 코드를 간략하게 편집한 것입니다. 따라서 권한 상승 코드는 보여주지 않았지요. 첨부된 소스 코드에 해당 코드가 포함되어 있습니다.

      잘 안되시면 사용하시는 실행환경을 좀 알려주시기 바랍니다.

      저도 좀 더 다양한 PC 환경에서 테스트 해보도록 하겠습니다.

      감사합니다.

  3. gg 2011/02/16 19:14 댓글주소 | 수정 | 삭제 | 댓글

    인젝션 함수에서 스레드 메모리 할당할때 스레드의 사이즈를 어떻게 구한건가요?
    (dword)인젝션함수 - (dword)스레드 라고 되어잇는데 이러면 단지 주소값을뺀건데
    자세한 설명부탁드림니다.

    • reversecore 2011/02/18 22:27 댓글주소 | 수정 | 삭제

      안녕하세요.

      네, 본문에는 문의하신 내용에 대한 설명이 부족하네요.

      인젝션 시킬 함수의 코드 크기를 구하면 되는건데요.

      일반적으로 C 언어 소스를 만들어 컴파일 하면 소스 순서대로 바이너리에 생성됩니다. 예를 들어 A(), B() C() 순으로 프로그래밍 되어있다면, 빌드된 바이너리에도 같은 순서대로 배치 된다는 뜻입니다.

      위 전체 코드를 받아보시면 ThreadProc() 함수 다음에 바로 InjectCode() 함수가 나타납니다.

      따라서 InjectCode - ThreadCode 는 ThreadCode() 함수의 크기로 볼 수 있는 것입니다.

      감사합니다.

  4. 2011/06/01 22:05 댓글주소 | 수정 | 삭제 | 댓글

    비밀댓글입니다

    • reversecore 2011/06/03 21:23 댓글주소 | 수정 | 삭제

      안녕하세요.

      개념은 잡으신것 같습니다. 실제로 그 의미를 정확히 이해하셔야 합니다. 왜? 정교하게 계산된 어셈블리 코드를 인젝션 해야 하는지? 왜? 함부로 API 호출 코드를 인젝션 하기 어려운지? 에대한 이유를 아셔야 합니다.

      감사합니다.

  5. 흠; 2011/07/18 22:53 댓글주소 | 수정 | 삭제 | 댓글

    .. 어렵군요 ! ㅠㅠ API 공부더하고와야하는가..

    • reversecore 2011/07/19 21:57 댓글주소 | 수정 | 삭제

      안녕하세요.

      위에 나온 내용은 사실 어렵습니다.

      기초 API Hooking 부터 차근차근 읽으시면 도움이 되실 것 같습니다.

      감사합니다.

  6. hyun 2011/09/22 23:23 댓글주소 | 수정 | 삭제 | 댓글

    정말 유익하게 보구 있습니다 ㅎㅎ

    악성코드를 치료하는 용도로 code injection 방법을 사용하려고 하는데요.
    악성 DLL이 특정 프로세스에 인젝션 되어 있는상태인데,
    제가 FreeLibrary를 호출하는 코드를 인젝트함으로써, 악성 DLL를 강제로 언로드 시킬수 있을까요?ㅎ

    • reversecore 2011/09/28 20:57 댓글주소 | 수정 | 삭제

      안녕하세요.

      악성코드의 자체 보호 기능이 없고, 다른 객체(파일, 네트워크, etc)를 열고 있지 않다면...
      강제로 인젝션 된 DLL 은 FreeLibrary() 로 다 내릴 수 있습니다.

      감사합니다.

  7. 저기요 2011/11/24 20:02 댓글주소 | 수정 | 삭제 | 댓글

    user32.dll 을 올렸는데 FreLibrary로 안내려줘도 괜찮은가요?
    또 VirtualAlloc으로 할당된 메모리도 해제해야 될거 같고
    메모장 종료되면 자동적으로 해제되는건가요?

    • reversecore 2011/11/30 01:47 댓글주소 | 수정 | 삭제

      안녕하세요.

      보통은 말씀하신대로 안쓰는 자원은 그때 그때 반환하는 것이 좋습니다.

      인젝션의 경우는 프로세스 종료 시 자동 해제되기 때문에 크게 신경쓰지 않는 것입니다. (필요하다면 이젝션 시켜서 자원을 반환하는 경우도 있습니다.)

      감사합니다.


Code Injection 기법 (1)

study 2010/06/22 00:25

Code Injection 기법에 대해 설명하고 실습 예제를 분석하겠습니다. DLL Injection 기법과 어떻게 다른지 비교 분석해보겠습니다.


* 본문 내용을 편하게 읽기 위해서는 아래의 배경지식이 필요합니다.




Code Injection


Code Injection 이란 상대방 프로세스에 독립 실행 코드를 삽입한 후 실행 시키는 기법입니다. 일반적으로 CreateRemoteThread() API 를 이용하여 원격 스레드 형태로 실행 시키므로 Thread Injection 이라고도 얘기합니다. 

아래 그림은 Code Injection 의 개념을 보여주고 있습니다.


<Fig. 1>

인젝션 대상이 되는 target.exe 프로세스에 코드와 데이터를 삽입합니다. 이때 코드의 형식은 스레드 프로시져(Thread Procedure) 형식으로 해주고, 코드에서 사용되는 데이터는 스레드의 파라미터로 전달해 주면 됩니다. 즉, 코드와 데이터를 각각 인젝션 시켜주는 것입니다.

이와 같이 개념은 간단한데, 구현에 있어서 주의해야 할 내용이 있습니다. Code Injection 구현의 주의 사항에 대해서 DLL Injection 과 비교하여 설명 드리겠습니다.




DLL Injection vs Code Injection


아래와 같이 간단한 코드가 있습니다. 코드의 내용은 윈도우 메시지 박스를 출력하는 것입니다.

DWORD WINAPI ThreadProc(LPVOID lParam)
{
    MessageBoxA(NULL, "www.reversecore.com", "ReverseCore", MB_OK);

    return 0;
}

DLL Injection 기법이라면 위 코드를 DLL 파일 형태로 만든 후 다른 프로세스에 인젝션 시키면 됩니다. 

OllyDbg 를 실행시켜 위 ThreadProc() 코드 영역을 살펴보겠습니다.

 
<Fig. 2>

위 그림의 코드에서 사용되는 주소를 주목하시기 바랍니다.

먼저 10001002 주소의 PUSH 10009290 명령어와 그 밑의 PUSH 1000929C 명령어에 사용된 10009290, 1000929C 주소를 보겠습니다. 이 명령어들은 MessageBoxA() API 에 사용될 문자열(“ReverseCore”, “www.reversecore.com”) 주소를 스택에 저장시킵니다.


<Fig. 3>

위 그림을 보시면 이 문자열들의 주소(10009290, 1000929C)는 DLL의 데이터 섹션 영역에 위치합니다. 

이번에는 <Fig. 2> 에서 1000100E 주소의 CALL DWORD PTR DS:[100080F0] 명령어에 사용된 100080F0 주소를 보겠습니다. 참고로 이 CALL 명령어는 바로 user32!MessageBoxA() API 호출 명령입니다.


<Fig. 4>

위 그림에서 100080F0 주소는 바로 DLL 의 IAT(Import Address Table) 영역임을 알 수 있습니다. (그 위로 다른 API 들의 주소를 확인 할 수 있습니다.)

이와 같이 DLL 의 코드에서 사용되는 모든 데이터는 DLL 의 데이터 영역에 위치합니다. 
따라서 DLL Injection 기법으로 DLL 을 통째로 상대방 프로세스 메모리에 삽입시키면 코드와 데이터가 같이 메모리에 존재하기 때문에 코드는 정상적으로 실행될 수 있습니다.

Code Injection 은 필요한 코드(<Fig. 2>)를 인젝션 시키는 것입니다. 하지만 코드에서 사용되는 데이터(<Fig. 3>, <Fig. 4>) 도 같이 인젝션 시켜줘야 정상적으로 코드의 실행이 가능해집니다. (또한 인젝션된 데이터의 주소를 코드에서 잘 알아볼 수 있도록 프로그래밍 해야 합니다.)

이러한 이유 때문에 DLL Injection 기법 보다 고려할 사항이 좀 더 많습니다.

아래의 실습 예제 코드를 보시면 더 확실히 파악하실 수 있습니다.



코드 인젝션을 사용하는 이유


코드 인젝션은 DLL 인젝션과 비교하여 기능은 비슷하면서 고려해야 할 사항은 더 많기 때문에 사용하기 불편하게 느껴질 수 있습니다. 과연 코드 인젝션의 장점은 무엇일까요?

1) 메모리를 적게 차지한다.

아주 작은 크기의 코드와 데이터를 인젝션 할 때는 DLL 로 만들어서 인젝션 시킬 필요가 없습니다. 간단히 코드 인젝션으로 구현하면 DLL 인젝션과 같은 기능을 제공하면서 메모리를 훨씬 적게 차지합니다.

2) 흔적을 찾기 어렵다.

DLL 인젝션은 해당 프로세스 메모리에 흔적을 남기기 때문에 간단히 인젝션 여부를 알 수 있습니다. 하지만 Code 인젝션은 쉽게 흔적을 남기지 않습니다. (물론 이 역시 알아낼 수 있는 방법이 있습니다.) 이 특징 때문에 악성코드에서도 코드 인젝션을 많이 사용합니다.

3) 기타

별도의 DLL 파일 없이 Code Injector 프로그램만 있으면 됩니다. 또한 처음에는 생소하지만 일단 익숙해 지게 되면 아주 쉽고 편리하게 구현이 가능합니다. 

간단히 정리하면 DLL Injection 은 규모가 크고 복잡한 일을 수행할 때 사용하고, Code Injection 은 규모가 작고 간단한 일을 수행할 때 사용합니다.



실습 예제(CodeInjection.exe)
 
실습 예제는 notepad.exe 프로세스에 간단한 코드를 인젝션 시켜서 메시지 박스를 출력하는 내용입니다.

* 참고!
CodeInjection.exe 는 Visual C++ 2008 Express Edition 으로 개발되었으며 Windows 7 32bit 환경에서 테스트 되었습니다. 

#1. notepad.exe 실행

notepad.exe 를 실행 시킨 후 Process Explorer 를 이용하여 notepad.exe 프로세스의 PID 를 확인합니다.


<Fig. 5>

제 테스트 환경에서 notepad.exe 의 PID 는 1896 입니다.

#2. CodeInjection.exe 실행

첨부된 CodeInjection.exe 파일을 실행시킵니다. 이때 실행 파라미터로 앞에서 구한 notepad.exe 의 PID 값을 입력합니다.


<Fig. 6>

#3. 메시지 박스 확인


<Fig. 7>

메시지 박스가 notepad.exe 윈도우의 밑에 깔려 있으므로 확인 하실 때 주의하시기 바랍니다.

다음 강좌에서 실습 예제의 소스 코드를 보면서 어떻게 구현되었는지 자세히 확인해 보도록 하겠습니다.


ReverseCore

위 글이 도움이 되셨다면 추천(VIEW ON) 부탁 드려요~

Trackback Address :: http://www.reversecore.com/trackback/81 관련글 쓰기

  1. L4c0 2010/06/22 10:20 댓글주소 | 수정 | 삭제 | 댓글

    재밌어요!!ㅎㅎ ^^

  2. Ezbeat 2010/06/22 12:45 댓글주소 | 수정 | 삭제 | 댓글

    드디어 코드인젝션 강의가 시작됬군요!! 쭉 읽어보면서 빼먹거나 몰랐던 내용도 있을거 같아서 꼼꼼히 읽어보고 갑니다~! ^^ 다음 강의도 기대할께요~!

  3. 흠; 2011/07/18 22:00 댓글주소 | 수정 | 삭제 | 댓글

    CreateRemoteThread<> fail : err_code = 5
    인젝션 차단된거같은대 흐음... 좋아할 일이겠지? 흠

  4. 흠; 2011/07/18 22:15 댓글주소 | 수정 | 삭제 | 댓글

    Oh , 곰오디오보안이 노트페드보다 못하군요 ㅋ
    곰오디오는 잘되네요 ㅋ

    • reversecore 2011/07/19 21:58 댓글주소 | 수정 | 삭제

      안녕하세요.

      아마 대부분의 프로세스에서는 DLL Injection 방어 기법이 없기 때문에 그대로 인젝션 될 것입니다.

      감사합니다.

  5. 2011/10/21 19:17 댓글주소 | 수정 | 삭제 | 댓글

    비밀댓글입니다