본문으로 바로가기

파일의 IT 블로그

  1. Home
  2. 데이터 과학/ChatGPT
  3. [ChatGPT] AI는 과연 난독화를 풀 수 있을까?

[ChatGPT] AI는 과연 난독화를 풀 수 있을까?

· 댓글개 · KRFile

최근 들어 스킨을 바꿨었는데 웹 소스를 수정하다가 난독화된 자바스크립트 코드를 발견하였습니다.

const _0x5898c3 = _0x418c;
(function (_0x18561e, _0x2f15cc) {
  const _0x273af5 = _0x418c, _0x563e33 = _0x18561e();
  while (true) {
    try {
      const _0x4b4332 = parseInt(_0x273af5(279)) / 1 * (-parseInt(_0x273af5(334)) / 2) + -parseInt(_0x273af5(320)) / 3 + -parseInt(_0x273af5(304)) / 4 * (parseInt(_0x273af5(284)) / 5) + -parseInt(_0x273af5(296)) / 6 + -parseInt(_0x273af5(321)) / 7 * (parseInt(_0x273af5(328)) / 8) + -parseInt(_0x273af5(306)) / 9 + parseInt(_0x273af5(287)) / 10 * (parseInt(_0x273af5(292)) / 11);
      if (_0x4b4332 === _0x2f15cc) break; else _0x563e33.push(_0x563e33.shift());
    } catch (_0x1cdbc3) {
      _0x563e33.push(_0x563e33.shift());
    }
  }
}(_0x32b6, 749130));
const observer2 = new MutationObserver(function (_0x226263) {
  const _0x4876f7 = _0x418c;
  ...

 

 

이미지 출처 : https://www.appsealing.com/code-obfuscation/

여기서 난독화란 아실 분들은 아시겠지만 코드를 읽기 어렵게 꼬아놓는걸 의미합니다. 보통 위 사진처럼 함수, 변수명만 바꿔놔도 읽기 싫어지고, 여기에 코드의 문자들을 Ascii 코드로 바꿔서 숫자 바이트로 바꿔버린 다음에 이걸 다시 원본 코드로 복구하는 형태로 꼬아놓는 경우도 있습니다;;

 

사실 작정하고 코드를 난독화 하면 끝도 없이 꼬아놓을 수 있기 때문에 난독화 도구 (난독화 해주는 프로그램 또는 사이트) 에 따라 출력이 천차만별로 달라집니다. 물론 난독화를 걸어도 읽기 어렵게만 해뒀을 뿐 당연히 원래 코드 기능이 달라지는건 아닙니다. 읽기만 어려워 져야지 난독화를 걸었을 때 내 코드 동작이 완전히 달라져버리면 안되는 거니깐요...

 

당연하지만 일반적인 이유로 난독화를 거는 경우는 없고 거의 99%가 보안 목적이라고 보시면 됩니다. 자바스크립트에 특히 난독화가 많이 걸려있는데 이유는 통신을 위해 거의 모든게 노출되는 웹 상, F12(개발자 도구)만 눌러도 그 웹 페이지에 대한 모든 HTML, CSS, JS 코드를 알 수 있기 때문입니다.

 

HTML, CSS는 눈에 보이는거라 그렇다 쳐도 Javascript 코드의 경우 클라이언트가 서버와 통신하거나 무언가 검증하는 코드가 들어있다 보니깐 웹 취약점이 노출 될 수 있어서 난독화를 거는 경우가 많습니다.

 

추가적으로 변수명을 a, b 와 같은 단순한 형태로 바꾸기 때문에 웹 통신시 불러와야 하는 자바스크립트 코드 글자수가 줄어들어서 웹 통신 속도를 올리는 장점까지 있습니다.

 

난독화를 거는 코드를 만든 사람만이 어떤 방식으로 난독화를 걸었는지 알기 때문에 푸는 방법 역시 본인만 알고 있습니다. (난독화를 거는 방법을 알고 있으니 이를 역순으로 다시 적용하면 난독화를 풀 수 있겠죠!)

 

그래서 난독화 도구를 배포하는 사람이 따로 난독화 하는 방법에 대해 알려주지 않으면, 출력 결과만 보고 난독화 시킨 방법을 유추해야 하기 때문에 난독화를 푸는 일은 매우 어렵습니다. 실행시켜서 기능을 보거나 디버깅을 걸어서 대충 유추해볼 수는 있겠습니다.

 

난독화를 푸는 일은 마치 마차에 1000겹 이상 엉켜있는 실을 푸는 기분, 해쉬 함수 출력값을 보고 입력 값을 찾아내는 기분이랄까요..

 

저처럼 스킨을 구매했는데 코드가 난독화 되어 있는 경우 스킨 제작자님한테 원본 코드를 요구해야 겠지만, 스킨을 건드는게 귀찮기도 하고 하는 일이 그렇게 많은 코드도 아닌 거 같아서 냅두고 있었습니다.

 

그러다가 문뜩 떠오른 생각이 혹시 ChatGPT.. 이녀석이 난독화를 풀 수 있지 않을까?

기계(CPU)는 난독화가 됐던 안됐던 간에 그냥 준대로 코드를 실행시키니깐..

 

https://twitter.com/alexalexandrius/status/1617876020593557506?s=46&t=HA9XuwgdwWWJrIuwK91wfQ

 

사실 ChatGPT로 난독화 해제에 희망을 가진건 이 트윗때문입니다. 난독화된 Node.js(Javascript) 코드를 줬더니 원본 코드로 난독화를 풀어버리더라구요 ㄷㄷ 단순히 질의한건 코드에 대한 설명 없이 De-obfuscate code below(아래에 적힌 코드 난독화 풀어봐.) 인데 말이죠

 

ChatGPT로 난독화 풀어보기

https://gist.github.com/alexandrius/01f9659f2e0a294da4c15713d59a6cbb

 

Obfuscated mongo db connection node

Obfuscated mongo db connection node. GitHub Gist: instantly share code, notes, and snippets.

gist.github.com

위 트윗에서 사용한 난독화 코드는 해당 링크에 있습니다.

 

일단 저도 ChatGPT한테 가서 똑같이 요청해보았습니다.

 

WOW 진짜 풀어주네요. 트윗과 동일한 코드를 출력하고 있습니다.

하지만 이정도 검증으론 부족하죠. 애초에 이 코드가 MongoClient 사용시 공식예제로 널리 퍼져있어서 ChatGPT가 학습하고 때려맞춘걸수도 있으니깐요. 

 

게다가 난독화를 건 코드에 MongoClient, mongodb 등 코드에서 사용하는 주요 키워드가 그대로 존재해서 강하게 난독화가 됐다고 보긴 어렵습니다.

 

제가 코드를 직접 작성하고 한번 요청해보겠습니다.

 

import axios from "axios";

const getPokemonData = async (id: number) => {
  try {
    const response = await axios.get(`https://pokeapi.co/api/v2/pokemon/${id}`);
    return response.data;
  } catch (error) {
    console.error(error);
  }
};

const fetchAllPokemonData = async () => {
  const pokemonIds = Array.from({ length: 200 }, (_, i) => i + 1);
  const promises = pokemonIds.map((id) => getPokemonData(id));
  const allPokemonData = await Promise.all(promises);
  return allPokemonData;
};

fetchAllPokemonData()
  .then((allPokemonData) => {
    console.log(allPokemonData);
  })
  .catch((error) => {
    console.error(error);
  });

우선 ChatGPT로 뽑아온 코드입니다. Promise와 비동기 개념을 활용해서 pokeapi 란 포켓몬 API 사이트? 에 가서 포켓몬 id번호 1번부터 200번까지 비동기적으로 한꺼번에 요청을 걸어서 결과값을 가져오는 Node.js(타입스크립트) 코드입니다.

코드 자체는 읽어볼 필요 없습니다. 어짜피 오늘 글은 난독화를 풀어내냐 못풀어내냐가 중요하기 때문에..

 

 

https://codebeautify.org/javascript-obfuscator

 

JavaScript Obfuscator Online: JS Code Obfuscator

Online JavaScript Obfuscator helps to encrypt JavaScript which make hard to read js code. It's obfuscate javascript code.

codebeautify.org

javascript를 난독화 해주는 웹 서비스가 많은데 저는 이것을 이용하도록 하겠습니다.

 

const _0x32bc2b = _0x566c;
(function(_0x2f671c, _0x37c472) {
    const _0x57aa7d = _0x566c,
        _0x56bfa8 = _0x2f671c();
    while (!![]) {
        try {
            const _0x478e95 = parseInt(_0x57aa7d(0xc8)) / (0x1990 + 0xd35 + -0x26c4) * (-parseInt(_0x57aa7d(0xbd)) / (-0x5cd + -0x9 * -0x29c + 0x1 * -0x11ad)) + parseInt(_0x57aa7d(0xb8)) / (-0xa17 + -0xd2c + -0x12 * -0x14b) + -parseInt(_0x57aa7d(0xb6)) / (-0x4b3 * -0x4 + -0x4 * 0x407 + -0x2ac) + parseInt(_0x57aa7d(0xc7)) / (0x12d1 * 0x2 + 0x1976 * -0x1 + 0x3d * -0x33) + -parseInt(_0x57aa7d(0xb9)) / (-0x1ee9 + 0x1bb6 + 0x339) * (-parseInt(_0x57aa7d(0xc1)) / (0x1626 + -0x1 * 0x1ef1 + 0x8d2 * 0x1)) + parseInt(_0x57aa7d(0xc2)) / (-0xb * -0x2a9 + 0x1103 + 0x7b5 * -0x6) * (-parseInt(_0x57aa7d(0xc5)) / (-0x48 * -0x13 + -0x8 * 0x277 + -0x7 * -0x20f)) + parseInt(_0x57aa7d(0xb4)) / (-0x7 * -0x236 + 0x8 * 0x40 + -0x2 * 0x8b8);
            if (_0x478e95 === _0x37c472) break;
            else _0x56bfa8['push'](_0x56bfa8['shift']());
        } catch (_0x339d9f) {
            _0x56bfa8['push'](_0x56bfa8['shift']());
        }
    }
}(_0x2f46, -0x1424b * 0x4 + -0x32d3b + 0x163f9 * 0xb));

function _0x566c(_0x5d66fc, _0x4552c1) {
    const _0xbf2cf3 = _0x2f46();
    return _0x566c = function(_0x577956, _0x1ef009) {
        _0x577956 = _0x577956 - (0x1d80 + -0x647 * -0x6 + 0x3 * -0x1628);
        let _0x23d540 = _0xbf2cf3[_0x577956];
        return _0x23d540;
    }, _0x566c(_0x5d66fc, _0x4552c1);
}
import _0x2aa717 from 'axios';

function _0x2f46() {
    const _0x58dab6 = ['all', 'mon/', 'error', '502033RlOmjr', '16mPwJxo', 'map', 'then', '2011941iSNERS', 'data', '132015FKcOyC', '146OQKDRo', 'keapi.co/a', 'get', '13891980bDShez', 'catch', '3489464WOQcUL', 'https://po', '1696617iRVQsD', '12EfUIMa', 'log', 'pi/v2/poke', 'from', '4670zNyIvr'];
    _0x2f46 = function() {
        return _0x58dab6;
    };
    return _0x2f46();
}
const getPokemonData = async _0x2c4473 => {
    const _0x2752df = _0x566c;
    try {
        const _0x213b94 = await _0x2aa717[_0x2752df(0xb3)](_0x2752df(0xb7) + _0x2752df(0xb2) + _0x2752df(0xbb) + _0x2752df(0xbf) + _0x2c4473);
        return _0x213b94[_0x2752df(0xc6)];
    } catch (_0x15de2c) {
        console[_0x2752df(0xc0)](_0x15de2c);
    }
}, fetchAllPokemonData = async () => {
    const _0x2898a0 = _0x566c,
        _0x55bcf8 = Array[_0x2898a0(0xbc)]({
            'length': 0xc8
        }, (_0x1880be, _0x1f5c1e) => _0x1f5c1e + (0x5 * 0x77a + 0x24ce + -0x4a2f)),
        _0x3b0a17 = _0x55bcf8[_0x2898a0(0xc3)](_0xd7132 => getPokemonData(_0xd7132)),
        _0x1b9f54 = await Promise[_0x2898a0(0xbe)](_0x3b0a17);
    return _0x1b9f54;
};
fetchAllPokemonData()[_0x32bc2b(0xc4)](_0x2f1be0 => {
    const _0x3a7565 = _0x32bc2b;
    console[_0x3a7565(0xba)](_0x2f1be0);
})[_0x32bc2b(0xb5)](_0x2ac173 => {
    const _0x2e8320 = _0x32bc2b;
    console[_0x2e8320(0xc0)](_0x2ac173);
});

코드를 난독화 해서 얻은 출력값 입니다.axios 나 함수 이름이 몇몇 그대로 유지되어 있긴 한데 이정도면 원래 코드에 비해 제대로 기능을 알아내는게 불가능할 수준입니다.

 

이제 이걸 ChatGPT 한테 줘서 난독화를 푸는지 확인해보겠습니다.

 

질의문은 아까전과 같습니다.

 

 

뭐야?? 진짜 풀었네 하고 봤는데 getPokemonData 함수는 원본과 동일하게 복원했으나 아쉽게도 fetchAllPokemonData 함수는 그 의미가 달라졌네요.

 

그래도 어느정도 가능성은 보았습니다. 난독화된 코드 자체가 인터넷에서 절대 사전 학습할 수 없는 데이터인데 GPT 모델이 어느정도 잘못된 정보를 섞어서 복구를 해주었다는 점이 인상깊네요

 

또한 아쉽게도 제 블로그 스킨에 있는 자바스크립트 코드는 그 의미를 해석하지 못했습니다.

위처럼 단순히 "난독화 풀어줘!" 이외에도 코드의 의미를 보충 설명하거나 자세하게 힌트를 줘서 난독화 해제를 요청했는데도 풀어내지 못하더라구요.

 

 

 

 

결론

- 인터넷에 널린코드나 어느정도 단순한 코드들은 비슷하게 난독화를 해제할 수 있다.

- 복잡하거나 아주 생소한 코드들은 난독화를 해제하지 못한다.

- 사람보단 나은데 GPT로 난독화가 안풀리면 인터넷에서 난독화 해제 도구(deobfuscator) 를 찾아야 한다. [원래 하던 방법 -.-]

 

여담 : ChatGPT 웹 버전은 GPT 3? 3.5 로 알고 있는데 나중에 GPT4 Waitlist 가 통과되면 GPT4로 난독화 해제도 한번 도전해볼까 싶습니다.

SNS 공유하기
💬 댓글 개
이모티콘창 닫기
울음
안녕
감사해요
당황
피폐

이모티콘을 클릭하면 댓글창에 입력됩니다.