Post

[Reversing] 리버싱을 위한 도구(IDA) 실습하기!

내 아이다

이전 글에서 공부한 내용

  • 리버싱(역공학) 기초 개념 이해
  • 대표적인 리버싱 도구 소개: IDA Free, Ghidra, Binary Ninja, x64dbg
  • IDA Free 설치 방법과 기본 사용법
  • 간단한 C 프로그램 컴파일 후 IDA에서 분석하기

그럼 이번에는 무엇을 할 것이냐? 지난번에는 지난번에는 솔직히 print("Hello, Reversing!") 같은 단순 출력문만 다뤄서 조금 재미가 없었단 말이죠. 고로 이번엔 if문을 곁들여 코드를 컴파일하고, 리버싱해보도록 합시다.

왜 굳이 if 문이죠?

인터넷에서 크랙이라는 이야기를 들어보신 적이 있을겁니다. 간단히 말해 크랙이란 프로그램을 사용하려고 할 때 정식 라이선스를 구매하지 않고도 인증 절차를 우회하거나 무력화하는 행위를 말합니다.

예를 들어, 유료 프로그램에 워터마크가 없으려면 라이선스 인증을 해야 하는데, 이 인증 부분을 불법적으로 리버싱해 넘겨뛰거나 아예 없애는 것이 바로 크랙입니다.

그리고 예상하셨겠지만, 이 인증이라는 과정은 결국 프로그램이 조건에 맞는지 확인하는 문제로, 바로 if문과 밀접한 관련이 있습니다.

그리고 우린 그걸 매~우 간단한 코드를 작성해 직접 실습해 볼겁니다!

C언어로 구현한 매우 간단한 IF문 문제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<stdio.h>
#include<windows.h>

int main()
{
    int password = 1234;

    if (password == 1234) {
        printf("Login Success.\n");
    } else {
        printf("Login Failed.\n");
    }

    Sleep(1000); // 1초 대기

    return 0;
}

지금 이 코드를 실행시켜 보면 당연하게도 로그인을 성공하게 될 것이다. 왜? 비밀번호가 1234인데 이미 password로 1234가 들어가있기 때문에!

그렇다면 만약에 비밀번호가 123으로 되어있다면? 당연하게도 로그인 실패가 뜰 것이다.

이제 직접 실행해보고 다음으로 IDA에서 열어보자.

IDA에서 분석해보기

자, 이제 위에서 작성한 C 코드를 컴파일한 .exe 파일을 IDA Free로 열어보도록 합시다.

여는 방법은 이 전 글을 읽고 왔다면 알겠죠?!

Image

처음 프로그램을 IDA에서 열게 되면 위 사진과 같은 화면이 나타납니다. 지금 보이는 부분은 main 함수에 해당하는 어셈블리 코드로, 우리가 작성한 조건문이 실제로 어떻게 변환되었는지를 보여주는 예시입니다.

그리고 이번에 우리는 IF문에 관한 흐름을 이해하기위해 그래프 뷰(Graph View)를 더 중점적으로 살펴보겠 습니다.

Image

위 이미지는 main 함수의 흐름을 그래프 형태로 시작화한 모습입니다. 그래프 뷰는 프로그램의 분기 구조를 블록 단위로 표현해주기 때문에 ifswitch, 반복문 같은 흐름 제어 구조를 이해할 때 매우 유용합니다.

  • 가장 위쪽 블록은 변수 초기화와 조건 비교를 담당합니다. (예: password == 1234)

  • 그 아래로 두 개의 블록이 분기되어 있는 것을 볼 수 있습니다. 조건이 참이면 왼쪽(성공), 거짓이면 오른쪽(실패)으로 흐름이 나뉘는 것이죠.

  • 마지막에는 다시 한 곳으로 합쳐지는 구조입니다. 즉, 성공이든 실패든 메시지를 출력한 뒤에는 동일한 경로로 프로그램이 종료됩니다.

그런데 저기 보이는 mov, push, cmp 이런게 뭔지 모르겠다고요? 이것들은 어셈블리어로 솔직히 말하자면 저도 잘 모른답니다. 필요할 때 마다 찾아보거나 자주 보던 것들만 알고 있을 뿐이죠.

그럼 이제 이 통과할 수 없는 로그인 부분을 통과할 수 있게 만들어야겠죠?! 그게 바로 우리의 목적이니까요!

흐름을 조작해보자 : 조건문 분석하기

Image

그래프 뷰의 첫 박스를 보면 맨 아래 부분에 mov, cmp 그리고 jnz라는 것이 있는데 이 다음에 나오는 것이 바로 여기로 갈까? 저기로 갈까? 하는 분기점이다.

mov는 변수 넣기를 하는 부분으로 현재 써있는 7Bh는 16비트로 우리가 설정했던 123 비밀번호다!

cmp는 두 값을 비교(CoMPare) 하는 명령이고, 여깄는 4D2h가 16진수로 하면 필요한 비밀번호인 1234가 된다!

jnzJump if Not Zero, 즉 비교한 값이 다르면 점프하라는 의미이다.

예를 들어, 우리가 작성한 코드에서 비밀번호가 1234가 아니면 “로그인 실패!”를 출력하라고 했죠? 그 부분이 바로 이 cmp + jnz 조합으로 어셈블리에서 구현된 것이다.

cmp     [rbp+var_4], 402h ; password 값과 1234를 비교
jnz     short loc_XXXX      ; 같지 않으면 실패 메시지로 점프

식의 구조라는 거죠!

흐름을 조작해보자 : 조건문 바꾸기

여기서 우리가 조작하고자 하는 부분은 바로 jnz 부분이 될 것이다. 여기서 뭐 위에 비교를 했던 아니던 그냥 원하는 부분으로 보내버리면 되기 때문이다.

Image

노란색으로 채크된 부분이 바로 지금 비교해서 로그인 실패 부분으로 보내는 과정이고 여기서 우리는 jmp라는 어셈블리어를 사용해서 비밀번호 확인을 할 때에 과정에 상관없이 점프시키도록 하겠다.

IDA에서 수정하는 방법

일단 패치를 하기 위해 Text View로 넘어가자. 단축키는 스페이스바

Image

이렇게 보일텐데 좀 어지러우니 사진을 더 키워보겠다.

Image

자 보아하니 우리가 바꾸고자 하는 jnz녀석이 보이고 분명 그 아래 바로 Login Sucess. 가 보이지만 loc_1400015BC로 점프하여 Login Failed를 띄워주고 있다. 괘씸하니 비번이 틀려도 바~로 아래부분의 위치로 이동시키게 만들어보자.

방법 1. jmp 사용하기 (이번 경우엔 불가!)

먼저 jnz무조건 점프하는 jmp로 바꿔보자.

Image

  1. jnz short loc_1400015BC 명령어 위에서 우클릭 → Assemble… 메뉴를 선택합니다.

패치하고 싶은 어셈블리어 코드에 마우스 커서를 누르고 IDA 상단의 Edit -> Patch Program -> Assemble을 눌러 편집을 할 수 있다.

Image

이렇게 뜨게 되고 여기서 우리가 바꿀 부분은 위에서 말했듯 jnzjmp로 바꾸고 그대로 ok를 누르면 그건 뒤에 나오는 1400015BC의 부분(로그인 실패)으로 보내져 버릴태니 사진에서 바로 다음 위치인 1400015AE로 보내버리자!

Image

바로 요렇게

어…?

Image

에…?

뭐가 문제일까?

여러번 시도해보니

1
2
3
4
5
6
7
8
9
10
11
jnz     short loc_1400015BC

-> 여기서

jmp     short loc_1400015BC

-> 이건 되는데

jnz     short loc_1400015AE

-> 이건 안되네?

이런 식이였다. 그리고 chatgpt에게 물어보자

와 정말 생각지도 못한 문제였다.

문제 원인

  1. 점프 거리 계산: jnz short loc_1400015AE에서 현재 위치(1400015AC)에서 목표 위치(1400015AE)까지의 거리는 1400015AE - 1400015AC = 2바이트입니다.

  2. 명령어 길이 고려: 하지만 실제로는 다음 명령어의 시작 주소를 기준으로 계산됩니다. jnz 명령어가 2바이트라면, 다음 명령어는 1400015AC + 2 = 1400015AE에서 시작됩니다.

  3. 상대 오프셋: 따라서 실제 계산은 1400015AE - 1400015AE = 0이 되어, 상대 오프셋이 0이 됩니다.

  4. Invalid Operation: 이는 유효하지 않은 점프 거리로 인식되어 “Invalid Operation” 오류가 발생합니다.

이런 순서로 문제가 생겼던 거다… 생각도 못했네..

방법 2. jz 사용하기 (조건 반전)

지금 조건은 비밀번호가 맞으면 통과하지만 만약 반대로 비밀번호가 틀리면 로그인이 된다면?

Image

이렇게 변경한 후에 패치 파일을 적용시키자.

edit -> Patch Program -> Apply patches to input file

Image

그리고 실행시키면? 성공이다!

정리하며

이번 실습을 통해 간단한 조건문(if)이 어셈블리에서 어떻게 분기 명령으로 바뀌는지, 그리고 그것을 IDA에서 직접 확인하고 수정(Patch)하는 방법까지 알아보았습니다.

사실 이런 간단한 if문도 리버싱에서는 매우 중요한 시작점입니다.
왜냐하면 수많은 인증 로직, 게임 내 조건 처리, 제한 해제 등 거의 모든 핵심 제어는 조건문으로 구현되어 있기 때문이죠!

IDA를 활용해 조건 흐름을 시각적으로 파악하고, 간단한 패치를 통해 흐름을 바꿔보는 경험을 해보셨으니 이제 전보단 아 이게 리버싱이구나 하는 느낌이 드실겁니다. 하지만 여기까지는 아직 초보자 단계라는점! 기초가 가장 중요하다고 합니다만 리버싱은 끝을 파고자 한다면 저 아래까지 내려가야한다고 하더군요.

다음번에는 [Reversing] Crackmes.one 문제 풀어보기 - Level 1와 같은 문제를 풀어보시기 바랍니다! 그렇게 차근차근 실력을 늘려나가는 거죠!

아 참고로 이 글을 작성하고 있는 2025-06-29기준으로는 아직 제가 저 부분에 ida를 이용한 방법을 넣지도 않았을 뿐더러 리버싱 공부하기 전에 머리박고 시작했던지라 인터넷에서 찾아 해보시기 바랍니다! 그럼 즐거운 해킹!

This post is licensed under CC BY 4.0 by the author.