• 티스토리 홈
  • 프로필사진
    satorare
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
satorare
  • 프로필사진
    satorare
    • 분류 전체보기 (8)
      • book (0)
      • Translate (2)
      • bin (6)
      • wargame (0)
      • ctf (0)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
      • ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⋯
      등록된 공지가 없습니다.
    # Home
    # 공지사항
    #
    # 태그
    # 검색결과
    # 방명록
    • rev-basic-4
      2022년 10월 24일
      • satorare
      • 작성자
      • 2022.10.24.:15

      IDA로 디컴파일링한 main함수

      main 함수의 전체적인 움직임은 v4라는 배열에다가 사용자로부터 받은 입력 문자열을 저장해둡니다. (라인 5~7)
      그 후, 함수 sub_140001000()을 통해서 키값을 대조하여 서로 맞는지 틀린지 비교하는 형태입니다.

      함수 sub_1400011C0()과 sub_140001220()은 자세히는 들여다 보지않았지만 아마 각각이 printf와 scanf와 비슷한 동작을 하는것으로 유추됩니다.

      키값을 알아내기 위하여 함수 sub_140001000()안을 살펴보겠습니다.

      함수 sub_140001000의 내부

      안에는 조건문이 또 하나 존재합니다.

      이를 보기쉽게 쓰면 다음과 같습니다.

      for ( i=0; i<28; ++i) {
      	if ((16 * al[i]) | (al[i] >> 4) != byte_140003000[i]){
        		return 0;
          }
      }
      return 1;


      >> 여기서 연산자 |은 OR 연산이며, 연산자 >>는 우측 시프트 연산입니다.

      인자로 받은 al 배열에 대해서 16을 곱한 값과, al 배열을 4만큼 우측 시프트 연산한 값을 OR연산을 하여
      이 값이 byte_140003000 배열의 문자열과 같은지 틀린지 확인하는 것입니다.

      먼저 역연산 과정을 생각해보겠습니다. al[i]를 P, byte_140003000[i]를 Q라고 하겠습니다. 이에 따르면

      (P * 16) | (P >> 4) = Q 이 때, P * 16이라는 연산은 조금 특이합니다. 예를들어 a라는 문자열을 들어보자면,

      a = 0110 0001 입니다. 여기다 16진수 16을 곱해주면 다음과 같습니다.

      a * 16 = 0110 0001 0000 왼쪽으로 4비트가 밀리고 그 자리가 0으로 채워졌습니다. 이는 좌측 시프트 연산(<<)과 동일한 동작입니다.

      즉,
      (P << 4) | (P >> 4) = Q 가 됩니다.

      여기서 직관적으로 봤을 때

      하나의 문자열을 왼쪽으로 4비트, 오른쪽으로 4비트 옮기는 각각의 행위는 마치 앞/뒤 4비트를 서로 바꾸는 것처럼 보여집니다.

      보다알기 쉽게 이러한 동작응 아까 문자열 a를 가지고 예로 들어보면, a = 0110 0001
      a << 4 = 0110 0001 0000
      a >> 4 = 0110 여기서 위로 가셔서 다시 조건문을 들여다보시면, 해당 조건문에 연산값을 unsigned int8로 캐스팅을 하는것을 볼 수 있습니다. 8비트만 보겠다는 얘기입니다.

      정리하자면 다음과 같습니다 a = 0110 0001 일 때,
      a << 4 = 0001 0000
      a >> 4 = 0000 0110

      각각의 시프트 연산을 거친 결과와 a를 비교해보면 문자열의 앞/뒤를 각각 표현하고있습니다.

      여기다 OR연산을 거쳤을 때 다음과 같습니다

      (a << 4) | (a >> 4) = 0001 0110

      처음 문자열 a와 정확히 앞/뒤 4비트가 서로 바뀌었습니다.

      이는 비단 a뿐만 아니라 아스키 코드 전부에 적용됩니다.

      최종적으로 우리에게 필요한 역연산 공식은 다음과 같습니다.

      (Q * 16) | (Q >> 4) = P

      이는 다시,
      (byte_140003000[i] * 16) | (byte_140003000[i] >> 4) = al[i]

      입니다.

      이제 배열 byte_140003000[]을 살펴보겠습니다.

      byte_140003000 배열의 내부


      반복문이 총 27회만 동작하므로, 뒤의 5개의 0은 제외하고 역연산 코드를 짰습니다.

      #include <stdio.h>
      
      int main(void) {
        unsigned char byte_140003000[27] = {
        36, 39, 19, 198, 198, 19, 22, 230, 71, 245, 38, 150, 71, 245, 70, 39, 19, 38, 38, 198, 86, 245, 195, 195, 245, 227, 227};
        for(int i = 0; i < 27; ++i) {
          printf("%c", (byte_140003000[i]*16) | (byte_140003000[i] >> 4));
        }
        printf("\n");
      }


      replit으로 테스트 결과 키값이 잘 출력됩니다.


      정답은 직접 해보시길 바랍니다

      'bin' 카테고리의 다른 글

      4. 소유권 이해하기  (0) 2022.10.26
      rev-basic-5  (0) 2022.10.25
      러스트 프로그래밍 가이드 연습문제 1 ~ 3  (0) 2022.10.23
      3. 보편적인 프로그래밍 개념  (0) 2022.10.23
      rev-basic-3  (0) 2022.10.23
      다음글
      다음 글이 없습니다.
      이전글
      이전 글이 없습니다.
      댓글
    조회된 결과가 없습니다.
    스킨 업데이트 안내
    현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
    ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
    목차
    표시할 목차가 없습니다.
      • 안녕하세요
      • 감사해요
      • 잘있어요

      티스토리툴바