콘텐츠로 건너뛰기

스크립트 분석: 압축과 난독화

  • 테크

웹 환경에서는 방문자 트래킹을 위한 JavaScript가 자주 삽입됩니다. 이러한 스크립트들은 방문자의 쿠키나 로컬스토리지를 활용해 세션 및 유입 경로를 기록하고, 서버로 로그를 전송함으로써 마케팅/광고 효과를 측정합니다. 대부분의 스크립트들은 메서드명 치환 등의 기법으로 코드 가독성을 의도적으로 낮춰 분석을 어렵게 만듭니다. 이번 포스팅에서는 압축과 난독화 기법을 살펴보고, 이러한 스크립트를 분석하는 일반적인 방법론에 대해 알아보겠습니다.

1. 압축과 난독화의 차이

1.1 압축

  • 공백/주석 제거, 변수명 축소 등을 통해 파일 크기를 최대한 줄이고 로딩 속도를 높이는 것을 목표로 합니다.
  • 예를 들어, 코드 길이를 줄이기 위해서 변수명을 a, b, c 처럼 간단한 문자로 바꿉니다.
  • 결과적으로 사람이 봤을 때 알아보기 불편하지만, 주 목적은 코드 크기 축소로딩 성능 개선에 있습니다.

1.2 난독화

  • 코드 가독성을 떨어뜨려 분석을 어렵게 만드는 것이 목표입니다.
  • 문자열·함수명 치환, 배열·인덱스 접근, 제어 흐름 변조, 동적(런타임) 디코딩 등 다양한 기법으로 코드를 이해하기 어렵게 만듭니다.
  • 동일한 기능이라도, 코드를 분석하고 수정하기 어렵게 만들어 코드를 보호하거나 역공학을 방해합니다.

2. 코드 구조 파악: 즉시실행 함수(IIFE)와 치환변수

2.1 즉시실행 함수 패턴

(function() {
  //...
})();
  • 많은 스크립트가 전역 스코프(오염) 방지를 위해 즉시실행 함수를 씌웁니다.
  • 내부에서 window.someObject = {…} 형태로 전역 객체를 만들고, 필요한 유틸 함수(쿠키·스토리지 제어, 이벤트 큐 처리 등)을 묶어 제공합니다.
  • IIFE를 사용하면 블록 내부의 변수나 함수를 외부에서 직접 접근하기 어렵게 만들 수 있어, 전체 코드 구조를 한눈에 보기 어렵게 하는 효과도 있습니다.

2.2 메서드명 치환 변수

var G = "apply", C = "call", z = "prototype";
function exampleFunc(arr) {
  return Object[z].toString[C](arr);
}
  • 원래는 Object.prototype.toString.call(arr)를 수행해야 하지만,
    z = “prototype”
    C = “call”
    로 치환하면 코드를 직접 해석해보지 않는 이상 어떤 메서드를 호출하는지 바로 이해하기 어려워집니다.

3. 주요 기능: 트래킹 로직과 데이터 전송

3.1 방문자 식별

  • 많은 트래킹 스크립트가 고유 ID(UUID, SID 등)를 생성하여 쿠키와 로컬스토리지에 저장합니다.
    (예시: 길이가 30~40자리 되는 무작위 문자열)
  • 새 방문 시에는 새로 생성하고, 이미 존재하면 해당 값을 재활용합니다.
  • 로컬스토리지에도 같은 값을 중복 저장하여, 브라우저가 쿠키를 차단하더라도 식별이 가능하도록 합니다.
  • 만료 시점을 체크해 일정 기간이 지나면 재발급하기도 하며, Chrome DevTools의 Application 탭에서 쿠키·스토리지 값이 어떻게 변하는지 확인할 수 있습니다.

3.2 이벤트 큐와 실행 시점 제어

var trackObj = window._trk = window._trk || function(){
  (window._trk.q = window._trk.q || []).push(arguments);
};

(function(){
  // script 로드가 끝나면 trackObj.q를 꺼내어 send 메서드 호출
})();
  • 일부 스크립트는 _trk 등의 이름으로 전역 함수(또는 객체)를 정의하고, 이벤트가 발생할 때마다 인자를 쌓아둡니다.
  • 아직 스크립트 초기화가 끝나지 않았거나 페이지 로딩이 덜 된 상황에서도 이벤트(클릭, 노출, 페이지뷰 등)을 빠르게 기록할 수 있습니다.
  • 페이지가 완전히 로드되거나 visibilitychange로 사용자가 실제로 페이지를 보는 시점을 감지해서, 한꺼번에 서버로 전송할 수 도 있습니다.

4. 난독화 요소와 해석 방법

4.1 문자열 변수 치환

var z = "prototype", C = "call";
// ...
Object[z].toString[C](someValue);
  • z가 뭘 의미하는지를 코드 상단에서 정의한 부분을 찾아 원상 복구해가면 해석할 수 있습니다.

4.2 런타임 동적 디코딩


var encodedScript = "KGZ1bmN0aW9uKCkgew0KICBjb25zb2xlLmxvZygiU2VjcmV0IE1lc3NhZ2UiKTsNCn0pKCk7";

function decodeBase64(str) {
  return atob(str);
}

(function() {
  var decoded = decodeBase64(encodedScript);
  eval(decoded);
})();
  • Base64로 인코딩된 스크립트 조각을 런타임에 해독하고 eval로 실행합니다.
  • 정적 분석 시에는 ‘encodedScript’라는 문자열만 보이므로, 실제 코드가 무엇을 하는지 쉽게 파악하기 어렵습니다.

5. 일반적인 분석 과정 요약

5.1 소스 포맷팅

  • 자동 정렬로 전체 코드 구조를 한눈에 파악할 수 있습니다.

5.2 전역 변수 확인

  • var G=”apply”, C=”call” 등 문자열 치환 여부를 확인합니다
  • window.someGlobal 등 외부로 노출되는 객체를 확인합니다.

5.3 핵심 함수 찾기

  • send, trk 등에서 라인 브레이크포인트를 설정합니다.
  • 함수가 언제, 어떤 인자로 호출되는지 실행 흐름 추적할 수 있습니다.

5.4 데이터 전송부 확인

  • XMLHttpRequest, fetch 를 검색합니다.
  • 네트워크 탭에서 어떤 파라미터(방문자 ID, Referrer, User-Agent 등)이 전송되는지 확인합니다.

5.5 정적·동적 분석 병행

  • 정적 분석: 변수명·함수명을 매핑하고, 흐름도를 작성합니다.
  • 동적 분석: 디버거로 실시간 값 확인하고, 호출 스택을 추적합니다.

이러한 과정을 거치면, 압축과 난독화가 적용된 트래킹·광고·분석 스크립트라도 의도와 데이터 흐름을 보다 명확하게 파악할 수 있습니다.

이번 포스팅에서는 압축 난독화가 이루어진 스크립트를 분석할 때의 전반적인 흐름과 주의할 점을 간단히 살펴보았습니다. 이런 스크립트는 한두 군데만 봐서는 정확히 무슨 일을 하는지 파악하기 어렵습니다. 앞서 살펴본 일반적인 접근법만 익혀두어도, 유사한 구조의 트래킹·광고·분석 스크립트를 보다 쉽게 이해하고, 잠재적 문제(개인정보 수집, 무분별한 트래픽 전송 등)를 파악할 수 있을 것입니다.

Ref.
Minify Resources
why-minify-javascript-code

최신 마케팅/고객 데이터 활용 사례를 받아보실 수 있습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다