By conchi | September 2, 2016
콘치의 리얼리티 3000% 리버싱 튜토리얼 (2)
안녕하세여.
지난시간에 듣기만 해도 현기증 날 거 같은 노잼 보스급 단어들로 여러분들을 긴장시키고 떠난 콘치가 2편을 들고 찾아왔어요 ^0^!!
2편은 리버싱 하기 전, 멘탈 챙기기 단계에요.
저야 브론즈 5(라 쓰고 심해라 읽는다)에서 지금 근 100판 가까이 게임을 하면서
이미 멘탈이 단련되어있는 상태기 때문에 이런 단계를 굳이 가지지 않아도 상관없어요.
음 이게 무슨 말이냐 하면 그냥 가진 것 없이 모든 것이 존재하는 무소유의 상태에 있기 때문에 멘탈을 챙길 필요가 없다는 소리에요.
저는 이런 상황이기 때문에 갑자기 어려운 것이 나와도 이것이 자연의 섭리이며 인생의 이치이거니 하며 조용히 습득하겠지만,
지난시간 까지만 해도 겨우 두 줄 되는 소스코드를 짜며
헤헤 이거 별거 아니네 코딩 ★정★복★ 하면서 모든 걸 안 사람마냥 신나있었던 여러분들이라면
아마 다시 인생의 나락으로 떨어질 가능성이 높기 때문에
본격 리버싱을 하기 전에 알아두어야 할 노잼보스급의 사전 지식들을 오늘 함께 알아볼까 해요.
지난번엔 “여러분들은 이제 모든걸 할 수 있을거에요!!” 하고 희망을 불어넣더니
오늘은 “님들은 겨우 개 코딱지만큼 따라한거니까 신나하지 마셈ㅎ!” 하고 있는 거 보니까
완전 어이없을 거에요 ㅎㅎ…
네 저도 어이없어요. ㅎㅎ..ㅋㅋ..
원래 이런 사람이니까 참고 하세여..ㅋㅋ…
# 이 인간 뭥미 …
[지난 시간 요약]
- 프로그램을 만들기 위해 신나게 Visual Studio 2015 Community 설치
- 신명나게 코딩도 해봄
- 소스코드를 한줄한줄 해석하던 중 전처리 지시자 라는 핵 노잼 냄새 나는 부분을 발견, 다음시간에 알아보아요. 여러분^^! 하고 도망감
- 브론즈5 탈출 하고 싶다
글은 겁나 길었던 것 같은데 요약을 해보니 저거밖에 안 되네요.
시무룩… 넘나 시무룩한 것..
괜찮아요. 오늘 이것저것 많이 할꺼니까!
[오늘의 준비물]
- 여러분의 유리 같은 멘탈과 하얗고 깨끗한 대뇌
지난시간 마지막 부분 기억 하시나요 혹시?!
소스코드를 한줄한줄 보던 중 소스코드의 맨 처음에는 # 으로 시작하는
전처리 지시자 가 들어간다고 말했잖아여!!
설마 기억안난다고 할꺼에요?ㅎㅎ?
(주먹을 쥐며)
오늘은 이 전처리지시자를 시작으로 프로그램은 어떤 과정을 거쳐서 만들어지는지 간단하게 알아보고
그 중에서도 우리가 눈여겨봐야 할 부분들이 어디인지
왜 눈여겨 봐야하는지에 대해 알아보고 다음시간 실제로 리버싱을 하게 되면 우리가 자주 보게 될 어셈블리나,
그때 사용하게 될 디버깅툴에 대해서 간단하게 이야기 해볼까 해요.
결국 이번시간에도 리버싱은 안 할 거란 소리를 뭔가 있어보이게 말 하고 있는 거에요ㅋㅋ!!
하지만 알아두면 언젠가는 다 써 먹을 데가 있을 테니 뒤로 가기 누르지 말고 야무지게 들어보도록 해요.
우리가 지난시간에 만든 몇 줄 안 되는…
막 허접해 보이는 소스코드에는 사실 놀라운 비밀이 숨어있어요!!
계속 반복해서 언급하고 있지만 컴퓨터는 우리가 코딩한 몇 줄 안 되는 C언어 소스 자체를 이해하지 못해요.
우리 눈에 보이는 언어들을 고급언어라고 했었고, 우리는 고급언어중 하나인 c언어로 프로그램을 만들었어요.
여기까지는 기억나죠?
계속 언급하지만 컴퓨터는 고급 언어를 이해하지 못해요.
그래서 고급언어 -> 어셈블리어 -> 기계어 이런 형태를 거쳐
자기가 알아 들을 수 있는 언어(기계어)로 번역해서 이해한 후 우리에게 결과를 보여주는 것이에요.
이쯤 되면 왠지 고급언어-> 어셈블리어 -> 기계어 로 변환 되는 과정에 뭔가 있을 것만 같은 냄새가 풀풀 나지 않나요?
안 난다구요?ㅋㅋ
사실 나도 안남ㅋ
조금 자세히 들여다보도록 해요 :)
우리가 만들었던 소스.c는 다음과 같은 과정을 거쳐 exe파일로 생성됩니다.
소스코드 -> 전처리기 -> 컴파일러 -> 어셈블러 -> 링커 -> 실행파일
전처리기는 지난번에 이야기했던 #이 붙는 전처리 명령들을 수행시켜주는 역할을 합니다.
전처리 명령은 어떤 형태로 컴파일을 할 것인지를 결정하거나,
여러 라이브러리 함수들을 이용하기 위해서 낭낭하게 함수에 대한 내용을
모아둔 파일(헤더파일)을 포함하는 등 여러 가지 상황에서 사용됩니다.
우리는 printf 라는 C표준 라이브러리 함수를 사용하기 위해서
이 함수가 정의 되어있는 stdio.h 파일을 사용하기 위해 #include라는 전처리 명령을 사용했었어요.
다들 기억나시죠? ^0^?! 안 나면 지금 마우스를 잡고 있는 여러분의 오른손으로
본인의 머리를 한 대만 쥐어 박아보세요 그럼 기억남ㅎㅎ.. (꿀팁!)
그런데 이거랑 리버싱이랑 무슨 상관이 있다는 거죠? 하고 생각되겠죠?
사실 리버싱할 때 어셈블리로 바꿔두면 이 부분은 나타나지도 않아서 눈에 보이지도 않는 부분들이에요.
그런데 이런 알 필요도 없어 보이는 부분들을 왜 언급하고 가냐면
여러분들 언제까지나 두 세줄 되는 프로그램만 리버싱할거 아니잖아요?
본인의 직업이나, 하는 작업에 따라 다양한 프로그램들을 리버싱 하게 될 텐데
그중에 ‘매크로’라는 기능을 사용하는 프로그램인 경우,
간혹 개발자가 구현한 코드와 컴퓨터가 이해한 코드가 다른 경우가 발생 할 수 있어요.
이 말은 그렇게 된다면 우리는 전혀 엉뚱한 방향으로 분석을 하게 될 수도 있다는 거에요…. 덜덜..
이럴 땐 본인이 직접 코드를 전처리기를 거치게 해서 결과를 확인하셔야 할 필요가 있어요.
음.. 이 내용은 우리 튜토리얼이 다루기에는 아직 먼 세계 이야기니까 아 이런 게 있구나,
이럴 수도 있구나. ㄷㄷ.. 뭐지.. 하고만 생각 하시면 될 것 같아요.
리버싱 안해야지! 이런 생각은 하지 마세요!!
헤헤!!
전처리기가 이런 전처리 지시자들을 해치우고 나면
.c였던 소스 파일은 .i형태로 바뀌게 됩니다.
이렇게 .i로 바뀐 파일은 컴파일러를 만나 새로운 언어로 변신하게 됩니다.
바로 우리가 앞으로 지겹도록 보게 될 어셈블리어로 말이에요.
쨔잔! 드디어 나옴 어셈블리어 ㅎㅎ!! 어셈블리어? 어셈블러? 어셈블리?
드라마 이름 아니세요? 하겠지만
ㄴㄴ 아님ㅎ 님 틀렸음(단호)
음.. 컴파일러의 역할을 대충 눈치 채셨나요?
컴파일러는 고급언어로 쓰인 프로그램을 어셈블리어로 바꾸어주는 번역 프로그램입니다.
이렇게 말하니까 무슨 말인지 잘 이해가 안 되네요.
사실 우리가 다운받았던 Visual Studio 2015 Community가 컴파일러입니다.
ㅇㅋ?
이해안된다구요?
왜죠? 아 ㅎㅎ 미안해여ㅎㅎ인성나옴;;;
ㅈㅅㅈㅅ 모를 수도 있어요.
ㅇㅇ.. 그렇다는.. ㅎㅎ!
여러분이 몰라야 제가 일을 합니다. 헤헤!!
컴파일러는 전처리기를 통해 한번 번역되어진 .i파일을 어셈블리어로 만듭니다.
기계어(0과 1로 이루어진 언어)로 되기 전에 한번 다른 언어로 번역 된다는 소리죠.
우리가 앞으로 계속계속 봐야할 어셈블리어로 말이에여. 호호 넘나 신나는 것!
아 컴퓨터는 왜 이런 귀찮은 작업을 해서 우리가 어셈블리 언어를 분석하게 하는 거야 - - + 하고 짜증나시는 분들 혹시 계시나요?
그럼 가서 기계어 보고 오셈 ㅎㅎ!! 안말림!!!
어셈블리어는 그나마 사람이 보고 이해 할 수 있으면서도 컴퓨터가 행동하게 될 움직임이랄까
그런 것 들을 직관적으로 파악 할 수 있는 언어입니다.
말로 하려니 설명이 안되네요.
이럴 때 만큼은.. 설명충이고 싶다..
어셈블리어에 대한 보다 자세한 내용은 다음 편에서 같이! 직접! 분석해가면서 어떻게 생겨먹었는데
컴퓨터가 하는 행동을 우리 눈으로 파악이 가능하나 한번 알아보도록 해여.
이거 알면 오히려 c언어로 프로그램 만드는 거 보다 더 쉬움!!
(하지만 콘치는 어셈으로 코딩을 하진 않는다고 한다ㅋ)
다음 편 허니잼 + 혼돈의 카오스 예상 ㅎㅎ!
위의 혼돈의 과정을 거쳐 어셈블리어가 된 소스는 .s라는 새로운 확장자를 득템 했습니다.
쨔쟌!
우리는 앞으로 기계어로 변환되기 전인 어셈블리어를 가지고 리버싱을 하게 될 거에요.
이 언어를 보고 이 프로그램이 어떤 역할을 하는지, 어떤 취약점이 존재하는지 등등을 찾아내는 거죠.
예? 저거만 보고 어떻게 알아내냐구요?
다 방법이 있어요. :3
아 물론 내가 할 줄 안다고는 말 안했음!!
우리 기술이사님이 이런 거 되게 잘하시는데… 읍읍..
어셈블리어는 이렇게 생겼어요.
영롱한 자태를 뽐내고 있군요. 흠.. 뭐라고 적혀있는지 잘 모르겠죠?..ㅎㅎ..
다음 편에서 자세하기 이야기 하고 저걸 이용해서 우리가 처음 코딩했던 소스로 돌아가는
충격적인 경험을 하게 해드릴 테니 지금은 그냥 눈 여겨 보고 넘어가도록 해요.
지금은 아! 이런 게 있구나 하고 넘어가시면 됩니다.
무튼 우리의 .c소스는 슬프게도 점점 알아보기 어려운 형태로 변하고 있네요.
하지만 우리가 보기에도 잘 모르겠는 이 어셈블리어를 컴퓨터는 아직도 못 알아먹어요.
더 기계스러운 언어로 변환을 해줘야하는데 이 역할은 어셈블러가 해줍니다.
어셈블러는 어셈블리어로 번역된 파일을 기계어로 번역해주는 역할을 합니다.
이제야 비로소 컴퓨터가 알아들을 수 있는 언어로 변하는거에요.
이때의 파일 확장자는 .o가 됩니다.
기계어는 0과1로 이루어져 있어요.
아마 기계어 파일을 열면 010101000101010110 막 이런 현기증 나는 숫자가 여러분들을 기다리고 있을거에요.
그럼 이제 컴퓨터가 알아들었으니 바로 .exe가 만들어지겠네요. 그쵸?
…는 훼이크! 마지막 과정이 남아있습니다.
실행을 가능하게 만들기 위해 .o로 변환된 파일을 함수라이브러리에서 가지고 온
개체 코드와 결합(링킹)시키는 과정을 거칩니다.
컴파일러가 만들어두었던 이런저런 결과물들을 하나로 연결시켜주는 역할을 하죠.
그러면 최종 프로그램 실행방식인 .exe가 탄생하게 됩니다!!
하지만 이런 복잡한 일들은 우리의 몫이 아니에요.
왜냐하면 코딩하고 [ctrl] + [f7] 눌러서 컴파일하고 [ctrl] + [f5] 누르면
자기가 알아서 실행파일을 만들어주잖아요ㅎㅎ!!
개이득 인정?
우리가 리버싱하기 위해 준비해야할 파일들은 이러한 고난을 통해 만들어진 .exe 파일들이에요.
이렇게 만들어진 파일들은 당연히 소스코드가 보이지 않아요.
여러분들 롤 하려고 실행파일 눌러도 소스코드가 튀어나오진 않잖아요? 같은 거에요. :3
심지어 방금 우리가 코딩한 파일은 .exe파일을 더블클릭 하면 까만 창이 떴다가
0.1초만에 사라지는 기적을 볼수 있을꺼에요.
(여러분이 만든 .exe파일은
C:\Users[여러분들 컴퓨터 이름]\Documents\Visual Studio 2015\Projects[여러분이 만든 프로젝트 이름]\Debug
안에 존재합니다.)
이거 뭐 실행도 안 되는 걸 가지고 와서 실행파일이라고 사기 치고 있어!!!
하시는 분들을 위해 우리가 코딩했던 hellow world!출력 프로그램 실행법도 알려드릴게요.
[시작] - [실행] - [cmd] - > cd ….\Debug – exe파일 앞 글자 누른 후 Tab버튼 누르면 자동완성까지 됩니당.
짜잔 이렇게 말이에요.
본론으로 돌아가서 이렇게 실행이 가능한 파일밖에 수중에 없는 우리는 어떻게 이 파일을 리버싱 해야할까요. 음… 막막하네요.
방법이 아주 없는 건 아니겠지만, 이건 좀 아닌 거 같아요. ㅎㅎ.. 지못미…
(이건 나중에 나말고 누가 따로 설명해주겠지..)
아까 실행파일이 만들어지던 과정을 곰곰이 되새겨 봅시다.
C언어가 기계어로 바뀌는 중간에 뭔가 이상하지만 그래도 눈으로 읽을 수는 있는 언어가 잠시 있었던 것 같은데…
네, 바로 그거에요. 그 녀석을 이용 하는 겁니다.
리버싱이란 결국 실행파일(.exe)을 어셈블리어로 바꾸어서 분석 하는거에요.
이 말을 하기 위해 위의 과정을 겁나 낭낭하게 이야기 했던거에요.
분해는 조립의 역순!! 따라서 조립하는 방법을 알아야 분해도 수월하게 할 수 있다고 생각한 콘치는
여러분들에게 핵노잼스러운 이야기들을 했던거에요.
뭐 사실 존엄하신 IDA님께선 실행파일만 던져도 C 소스로 바꾸어 주십니다.
하지만 존엄하신 만큼 몸값이 어메이징하다는점… 따라서 가난한 우리는 무료 디버깅 툴들을 이용해서 ㅠㅠ
어셈블리어를 보면서 IDA님께서 C코드로 바꾸어 주시듯이 리버싱을 할 계획이에요. 호롤롤롤
그런데.. 뀨? 디버깅이 뭐냐구요?
디버깅은 디버거(Debugger)를 이용해서 프로그램의 내부를 샅샅이 파헤치고 구경하고 씹고 뜯고 맛보고 즐기는 행위를 말해요.
이런걸 할수 있게끔 해주는 툴이 디버깅 툴이죠!
디버거를 이용하면 동적으로 프로그램을 분석 할 수 있게 됩니다.
이런 과정을 통해서 우리는 프로그램에서 발생가능한 취약점도 찾고, 버그도 찾고 해염.
디버거에는 보통 디스어셈블러 기능이 들어있습니다. 그래서 기계어가 되어버린 소스코드를
그나마 우리 눈으로 볼 수 있는 어셈블리어로 보여주기 때문에 이런 일들이 가능한거에요.
우리는 다음시간부터 무료 디버거 툴을 이용해서 프로그램을 분석해 볼거에요. 유후!
그리고 마지막으로 정말 중요하니까 한번 만 더 어셈블리언어에 대해 이야기 하고 갈게요.
어셈블리어는 위에서도 계속 설명했지만 우리가 이해하지 못하는 기계어(2진수로 되어있음…0과 1의 향연이랄까)를
그나마 사람이 알아 볼 수 있게끔 문자로 나타낸 언어입니다.
저는 그래도 무슨 말인지 잘 못 알아 듣는 경향이 없지 않아 있다는게 문제지만…
사실 뭔 말인지 이해하기가 처음에는 어렵지만 자꾸 보다 보면 어셈블리어 만큼 직관적인 언어도 없는 거 같아요.
여러분들도 다음시간부터 같이 보면 알겠지만 정말 고급언어로 코딩한 기능이 레지스터에 어떻게 들어가고,
어떻게 소스코드가 실행되는지 정말 적나라하게 보여주고 있어요.
처음에야 뭐.. “극혐!”이러겠지만 어느 순간 와 이건 뭐지? 하고 어셈블리 코드를 사랑스런 눈으로 보고 있는 여러분들을 볼 수 있을거에요.
남들 앞에서 이런 말 하면 변태 같다고 하니까 속으로만 생각하셈.
우리가 자주보게 될 어셈블리어로는 ADD, SUB, MOV, CALL, PUSH, JMP이런 친구들이 있답니다.
이름 그대로 값을 더하고, 빼고, 이동하고, 호출하고, 넣고, 점프하는 그런
기능들을 가지고 있어요ㅋㅋㅋ 헐 이름값 하는 거 좀 보소ㅋㅋ
자세한 기능들은 다음시간에 직접 해보면서 하나하나 알아보도록 해용 :)
뿅!