> 웹 프론트엔드 > JS 튜토리얼 > 실험실을 번거롭게 하지 않고 JavaScript로 난독화를 만드는 방법은 다음과 같습니다: AST, Babel, 플러그인.

실험실을 번거롭게 하지 않고 JavaScript로 난독화를 만드는 방법은 다음과 같습니다: AST, Babel, 플러그인.

DDD
풀어 주다: 2025-01-10 12:34:44
원래의
146명이 탐색했습니다.

소개

안녕하세요, 당신의 알고리즘이 얼마나 멋지고 독특한지 생각해 본 적이 있나요? ? 많은 프로그래머와 회사가 그렇게 하기 때문에 자신의 작업을 모든 사람과 공유하는 것을 주저할 수 있습니다. 코드의 일부가 서버(클라이언트-서버 애플리케이션의 경우)로 이동하면 이 문제가 조금 더 나아지지만 이 접근 방식이 항상 가능한 것은 아닙니다. 때로는 민감한 코드 섹션을 바로 공개해야 하는 경우도 있습니다.

이 기사에서는 JavaScript의 난독화에 대해 살펴보고 알고리즘을 숨기고 코드 연구를 더 어렵게 만드는 방법을 살펴보겠습니다. 또한 AST가 무엇인지 알아보고 난독화 구현을 위해 AST와 상호 작용하는 데 사용할 수 있는 도구를 제공할 것입니다.

무슨 일이야?

여기 어리석은 예가 있습니다. 이런 상황을 상상해 봅시다:

  1. Bob은 컴퓨터 모니터를 증정하는 사이트로 이동합니다(여기는 -> ?). Bob의 모니터는 더 좋지만 무료 제품은 언제나 좋습니다!
  2. Bob이 사이트를 방문하면 브라우저에서 JavaScript가 실행되어 사용자 기기에 대한 데이터를 수집하여 서버로 보냅니다. 이것이 바로 다음과 같다고 가정해 보겠습니다.
let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
  1. 안타깝게도 Bob은 경품 페이지에 액세스할 수 없어 상당히 화가 났습니다. 그는 이유를 이해하지 못합니다. 그러다가 그는 크고 좋은 모니터를 가진 사용자는 허용되지 않는다는 경품 규칙을 알게 됩니다.

  2. 다행히 Bob은 고등학교 때 컴퓨터 과학 수업을 몇 개 수강했습니다. 그는 F12 키를 눌러 과감하게 개발자 콘솔을 열고 스크립트를 연구하고 주최자가 화면 해상도를 확인한다는 것을 깨닫습니다. 그런 다음 그는 휴대전화로 참여하기로 결정하고 테스트를 성공적으로 통과했습니다.

해피엔딩으로 끝나는 가상의 이야기 - 하지만 주인공이 이전 코드 대신 이것을 보았다면 이보다 좋을 수 없었을 것입니다:

l=~[];l={___:++l,$$$$:(![]+"")[l],__$:++l,$_$_:(![]+"")[l],_$_:++l,$_$$:({}+"")[l],$$_$:(l[l]+"")[l],_$$:++l,$$$_:(!""+"")[l],$__:++l,$_$:++l,$$__:({}+"")[l],$$_:++l,$$$:++l,$___:++l,$__$:++l};l.$_=(l.$_=l+"")[l.$_$]+(l._$=l.$_[l.__$])+(l.$$=(l.$+"")[l.__$])+((!l)+"")[l._$$]+(l.__=l.$_[l.$$_])+(l.$=(!""+"")[l.__$])+(l._=(!""+"")[l._$_])+l.$_[l.$_$]+l.__+l._$+l.$;l.$$=l.$+(!""+"")[l._$$]+l.__+l._+l.$+l.$$;l.$=(l.___)[l.$_][l.$_];l.$(l.$(l.$$+"\""+(![]+"")[l._$_]+l.$$$_+l.__+"\"+l.$__+l.___+"\"+l.__$+l.$$_+l.$$$+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$$_+l.$$$+"\"+l.__$+l.$_$+l.__$+l.$$_$+l.__+"\"+l.__$+l.$_$+l.___+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$_$+l.___+l.$$$_+"\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$__+l.$$$+"\"+l.__$+l.$_$+l.___+l.__+";\"+l.__$+l._$_+l.$$__+l._$+"\"+l.__$+l.$_$+l.$$_+"\"+l.__$+l.$$_+l._$$+l._$+(![]+"")[l._$_]+l.$$$_+".\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$_$+l.$$_+l.$$$$+l._$+"(\"+l.__$+l.$$_+l.$$$+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+");"+"\"")())();
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

Here
장담하는데, 이건 횡설수설이 아니라 JavaScript입니다! 그리고 동일한 작업을 수행합니다. 여기 콘솔에서 코드를 실행해볼 수 있습니다.

이런 경우 우리 영웅은 경품 행사에 참여하지 않고 자신의 운명을 받아들였을 것이고 주최측에서는 계획을 지켰을 것입니다.

그럼 여기서 요점은 무엇인가요? 축하합니다. jjencode 도구와 난독화가 무엇인지, 어떤 역할을 할 수 있는지 알아보았습니다.

요약하면 난독화는 프로그램 코드나 데이터를 사람이 이해하기 어렵지만 기계나 프로그램에서는 작동하는 형식으로 변환하는 프로세스입니다.

비밀을 숨기고 있습니다. 빠른 방법

이론은 이쯤하고 좀 더 실제적인 예로 넘어가 볼까요?‍?. 이제 인터넷에서 쉽게 찾을 수 있는 난독화를 사용하여 코드를 변환해 보겠습니다. 우리의 "노하우" 작업이 포함된 좀 더 흥미로운 코드를 살펴보겠습니다. 그리고 F12에 도달하기에는 너무 게으르지 않은 모든 사람이 이에 대해 알 수 있다는 것은 매우 바람직하지 않습니다.

let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이 코드는 장치 및 브라우저 데이터를 수집하고 결과를 콘솔에 출력합니다. 예를 들어(출력을 코드 성능의 지표로 사용합니다)

l=~[];l={___:++l,$$$$:(![]+"")[l],__$:++l,$_$_:(![]+"")[l],_$_:++l,$_$$:({}+"")[l],$$_$:(l[l]+"")[l],_$$:++l,$$$_:(!""+"")[l],$__:++l,$_$:++l,$$__:({}+"")[l],$$_:++l,$$$:++l,$___:++l,$__$:++l};l.$_=(l.$_=l+"")[l.$_$]+(l._$=l.$_[l.__$])+(l.$$=(l.$+"")[l.__$])+((!l)+"")[l._$$]+(l.__=l.$_[l.$$_])+(l.$=(!""+"")[l.__$])+(l._=(!""+"")[l._$_])+l.$_[l.$_$]+l.__+l._$+l.$;l.$$=l.$+(!""+"")[l._$$]+l.__+l._+l.$+l.$$;l.$=(l.___)[l.$_][l.$_];l.$(l.$(l.$$+"\""+(![]+"")[l._$_]+l.$$$_+l.__+"\"+l.$__+l.___+"\"+l.__$+l.$$_+l.$$$+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$$_+l.$$$+"\"+l.__$+l.$_$+l.__$+l.$$_$+l.__+"\"+l.__$+l.$_$+l.___+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$_$+l.___+l.$$$_+"\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$__+l.$$$+"\"+l.__$+l.$_$+l.___+l.__+";\"+l.__$+l._$_+l.$$__+l._$+"\"+l.__$+l.$_$+l.$$_+"\"+l.__$+l.$$_+l._$$+l._$+(![]+"")[l._$_]+l.$$$_+".\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$_$+l.$$_+l.$$$$+l._$+"(\"+l.__$+l.$$_+l.$$$+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+");"+"\"")())();
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이제 위 코드를 가져와 인기 있는 JS용 난독 처리기인 obfuscator.io로 수정해 보겠습니다. 결과적으로 다음과 같은 코드를 얻게 됩니다.

function getGpuData(){
  let cnv = document.createElement("canvas");
  let ctx = cnv.getContext("webgl");
  const rendererInfo = ctx.getParameter(ctx.RENDERER);
  const vendorInfo = ctx.getParameter(ctx.VENDOR);

  return [rendererInfo, vendorInfo]
}

function getLanguages(){
  return window.navigator.languages;
}

let data = {};
data.gpu = getGpuData();
data.langs = getLanguages();
console.log(JSON.stringify(data))
로그인 후 복사
로그인 후 복사

짜잔! 이제 기계만이 이 코드를 기꺼이 구문 분석할 수 있습니다(당신과 나는 아마도 그들 중 하나가 아닐 것입니다 ?). 그럼에도 불구하고 여전히 작동하며 동일한 결과를 생성합니다. 변경 사항을 확인하세요.

  1. 줄바꿈과 추가 공백이 사라졌습니다.
  2. 변수 이름은 _0x587f42와 같이 정보가 없는 이름으로 대체되었습니다.
  3. 문자열과 객체 속성은 인덱스별로 배열의 값을 반환하는 함수 호출로 변환되었습니다. 예를 들어 document.createElement("canvas")는 document[_0x12260c(0x197)](_0x12260c(0x191))로 변환됩니다. 이는 계산된 속성을 사용함으로써 가능했습니다.

이 경우 정적 코드 분석에 부담을 준다는 점에서 마지막 기술이 아마도 가장 불쾌할 것입니다.

알겠습니다. 모든 비밀이 숨겨져 있는 것 같습니다. 코드를 프로덕션에 배포해볼까요?

잠깐만요... 코드 난독화를 위한 서비스가 있다면 이 기능을 되돌릴 수 있는 서비스가 있을까요? 물론 ?, 그리고 하나 이상! 그중 하나인 webcrack을 사용해 보겠습니다. 그리고 읽을 수 있는 원본 코드를 얻을 수 있는지 확인하세요. 다음은 이 deobfuscator를 사용한 결과입니다.

{"gpu":["ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar","Mozilla"],"langs":["en-US","en"]}
로그인 후 복사
로그인 후 복사

?. 물론 변수명을 돌려주지는 않았지만, 고마워요.

그래서 이 경우 코드를 침착하게 연구하는 데 유일한 장애물은 난독화 장치를 사용하려는 연구원의 의지라는 것이 밝혀졌습니다. 의심할 여지 없이 다른 솔루션과 사용자 정의를 사용하는 것도 가능하지만 대중적인 난독화의 경우 대중적인 난독화를 기대할 가능성이 높습니다.

싸우지도 않고 절망하고 비밀을 포기해야 할까요? 물론 그렇지 않습니다! 우리가 무엇을 더 할 수 있는지 봅시다....

Here

난독 처리자가되는 방법

난독처리기 - 마치 판타지 세계의 마법사처럼 들리지 않나요? ??‍♂️
확실히 누군가는 코드를 작성하는 동안 코드를 난독화할 수 있으며 타고난 마술사입니다. 당신은 의도치 않게 한동안 스스로 그러한 주문을 시전할 수 있었을 수도 있습니다. 그런데 '선임 프로그래머'들의 비판으로 인해 그 기술이 사라졌고 잠재적으로 프로그램을 조사하기 어렵게 만들 수 있는 아이디어가 있다면 어떻게 해야 할까요? 이 경우 코드 구조 자체와 상호 작용하고 이를 수정할 수 있는 도구를 사용하는 것이 합리적입니다. 살펴보겠습니다.

AS도구

단순히 텍스트처럼 코드와 상호 작용하고 특정 구성을 정규식으로 바꾸는 등의 방법으로 코드를 수정하는 것도 가능합니다. 하지만 이 방법을 따르면 난독화하는 것보다 코드와 시간을 망칠 가능성이 더 높습니다.

보다 안정적이고 제어된 수정을 위해 이를 추상 구조인 트리(AST - 추상 구문 트리)로 가져와서 관심 있는 요소와 구성을 변경할 수 있는 것이 좋습니다. .

JS 코드 작업에는 다양한 솔루션이 있으며 최종 AST에는 차이가 있습니다. 이번 글에서는 이를 위해 babel을 사용하겠습니다. 아무것도 설치할 필요가 없으며 astexplorer와 같은 리소스에서 모든 것을 실험해 볼 수 있습니다.

(바벨을 엉망으로 만들고 싶지 않다면 Shift-refactor를 확인하세요. **CSS 선택기를 사용하여 AST와 상호 작용할 수 있습니다. 학습을 위한 아주 최소한이고 편리한 접근 방식 그러나 바벨과 다른 특정 버전의 AST를 사용합니다. Shift-query 대화형 데모에서 이 도구에 대한 CSS 쿼리를 테스트할 수 있습니다.

0. AST와 협력하기

이제 간단한 예를 통해 브라우저를 떠나지 않고도 이러한 도구를 쉽게 사용할 수 있는 방법을 살펴보겠습니다. 동일한 이름의 함수에서 테스트 변수의 이름을 변경됨으로 변경해야 한다고 가정해 보겠습니다.

let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이 코드를 astexplorer에 붙여넣으면(위에서 JavaScript@babel/parser 선택) 거기에 AST로 표시되어야 합니다. 테스트 변수를 클릭하면 오른쪽 창에서 이 코드 섹션의 구문을 볼 수 있습니다.
Here

문제를 해결하기 위해 다음 babel 플러그인을 작성할 수 있습니다. 이 플러그인은 코드를 구문 분석하고 그 안의 모든 이름 식별자를 찾아 특정 조건이 충족되면 이름을 바꿉니다. astexplorer의 왼쪽 하단 창에 붙여넣습니다(transform 슬라이더를 켜고 babelv7을 선택하여 표시합니다).

let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이 플러그인에는 콘솔 출력이 포함된 이유가 있습니다. 이를 통해 브라우저 콘솔에서 출력을 검사하여 플러그인을 디버깅할 수 있습니다. 이 경우 식별자 유형의 모든 노드에 대한 정보를 출력합니다. 이 정보에는 노드 자체(node), 상위 노드(parent) 및 환경(범위 - 현재 컨텍스트에서 생성된 변수 및 이에 대한 참조 포함)에 대한 데이터가 포함됩니다.
Here

따라서 오른쪽 하단 창에서 다른 식별자에 영향을 주지 않고 소스 코드의 변수가 성공적으로 변경되었음을 확인할 수 있습니다.

l=~[];l={___:++l,$$$$:(![]+"")[l],__$:++l,$_$_:(![]+"")[l],_$_:++l,$_$$:({}+"")[l],$$_$:(l[l]+"")[l],_$$:++l,$$$_:(!""+"")[l],$__:++l,$_$:++l,$$__:({}+"")[l],$$_:++l,$$$:++l,$___:++l,$__$:++l};l.$_=(l.$_=l+"")[l.$_$]+(l._$=l.$_[l.__$])+(l.$$=(l.$+"")[l.__$])+((!l)+"")[l._$$]+(l.__=l.$_[l.$$_])+(l.$=(!""+"")[l.__$])+(l._=(!""+"")[l._$_])+l.$_[l.$_$]+l.__+l._$+l.$;l.$$=l.$+(!""+"")[l._$$]+l.__+l._+l.$+l.$$;l.$=(l.___)[l.$_][l.$_];l.$(l.$(l.$$+"\""+(![]+"")[l._$_]+l.$$$_+l.__+"\"+l.$__+l.___+"\"+l.__$+l.$$_+l.$$$+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$$_+l.$$$+"\"+l.__$+l.$_$+l.__$+l.$$_$+l.__+"\"+l.__$+l.$_$+l.___+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$_$+l.___+l.$$$_+"\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$__+l.$$$+"\"+l.__$+l.$_$+l.___+l.__+";\"+l.__$+l._$_+l.$$__+l._$+"\"+l.__$+l.$_$+l.$$_+"\"+l.__$+l.$$_+l._$$+l._$+(![]+"")[l._$_]+l.$$$_+".\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$_$+l.$$_+l.$$$$+l._$+"(\"+l.__$+l.$$_+l.$$$+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+");"+"\"")())();
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이 예를 바탕으로 코드를 구문 분석하고 수정하는 방법이 조금 더 명확해졌기를 바랍니다. 어쨌든 완료된 작업을 요약하겠습니다.

  1. asexplorer를 통해 babel을 사용하여 코드를 AST로 변환했습니다.
  2. AST를 조사한 결과 테스트 변수에 식별자 유형으로 레이블이 지정되어 있으며 이름 속성을 사용하여 이름을 정의할 수 있음을 확인했습니다.
  3. 다음으로 babel 플러그인을 사용하여 모든 식별자를 우회하고 이름이 test인 함수의 식별자 이름을 변경됨으로 변경했습니다.

1. 함수 및 변수 이름 숨기기

이제 코드 수정 방법이 명확해졌습니다. 난독화라고 부를 수 있는 좀 더 유용한 것을 시도해 보겠습니다 :) 이전 섹션에서 난독화하려고 시도한 더 복잡한 코드를 사용하겠습니다. 이제 그 안에 있는 모든 변수와 함수의 이름을 임의의 이름으로 변경하겠습니다. 따라서 잠재적인 리버스 엔지니어는 일부 코드 요소의 목적에 대한 정보가 더 적습니다.

또한 JS 코드를 자유롭게 사용하여 문제를 디버깅할 수 있습니다. 고통만큼 좋은 스승은 없다고 ?.

다음 플러그인은 작업을 완료하는 데 도움이 됩니다.

function getGpuData(){
  let cnv = document.createElement("canvas");
  let ctx = cnv.getContext("webgl");
  const rendererInfo = ctx.getParameter(ctx.RENDERER);
  const vendorInfo = ctx.getParameter(ctx.VENDOR);

  return [rendererInfo, vendorInfo]
}

function getLanguages(){
  return window.navigator.languages;
}

let data = {};
data.gpu = getGpuData();
data.langs = getLanguages();
console.log(JSON.stringify(data))
로그인 후 복사
로그인 후 복사

이 코드의 역할은 무엇인가요? 이전 예와 거의 동일합니다.

  1. 식별자 유형의 모든 AST 노드를 통과합니다.
  2. 이번에는 generateRndName 함수를 사용하여 조건 없이 식별자 이름을 무작위로 생성해 보겠습니다.
  3. 고유한 이름을 생성하면 프로그램 논리를 깨뜨릴 수 있는 중복된 이름을 무작위로 얻지 못하게 됩니다.

플러그인 실행 결과, 임의의 변수 이름과 함수가 포함된 다음 코드를 얻습니다.

{"gpu":["ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar","Mozilla"],"langs":["en-US","en"]}
로그인 후 복사
로그인 후 복사

콘솔에서 코드를 실행하여 확인할 수 있습니다. 조작 후에도 여전히 작동합니다! 그리고 이것이 좋은 난독화 장치의 주요 품질입니다 ✨.

그런데 난독화의 품질은 어떻습니까? 나로서는 악이 아직 그렇게 강하지 않다. 이름을 바꾸더라도 숙련된 프로그래머라면 이 코드의 목적을 쉽게 이해할 수 있을 것이다. JS 축소기가 이 작업을 처리할 수 있다면 무슨 의미가 있을까요? 이제 리버서에 대해 좀 더 실용적이고 번거로운 작업을 수행하는 것이 가능합니까? 주문이 하나 더 있어요...

Here

2. 숨기기? 모든 것!

“모든 것”이라고 썼을 때는 조금 자신 있었을지 모르지만, 지금 우리가 할 일은 코드의 동작을 최대한 숨기는 것입니다. 이 섹션에서는 정적 분석을 복잡하게 하고 "클라이언트"가 코드를 파고드는 것을 잠재적으로 방지하기 위해 문자열과 다양한 개체 속성을 숨길 것입니다!

이전 단계에서 얻은 숨겨진 이름이 포함된 코드에 다음 플러그인을 적용해 보겠습니다.

let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이미 코드 주석에서 이 플러그인의 작업을 조금 설명했지만, 이 플러그인이 수행하는 작업을 단계별로 간략하게 설명하겠습니다.

  1. 코드에서 대체할 모든 속성과 문자열을 저장할 배열 데이터를 만듭니다. 이 배열은 데이터를 반환하는 getData 함수에서 사용됩니다.
  2. 다음으로 AST를 탐색하여 코드 시작 부분에 getData 함수(주어진 인덱스의 속성과 문자열 반환)가 삽입될 루트 노드 프로그램을 찾습니다.
  3. 그런 다음 MemberExpression 유형의 노드를 우회합니다. 속성을 getData 함수 호출로 대체합니다. 이 경우 계산된 속성 덕분에 document.createElement와 같은 구성은 document[getData(0)]로 변환됩니다. 그 과정에서 속성 이름을 데이터 배열에 넣습니다.
  4. 마지막으로 StringLiteral 유형의 노드를 우회합니다. 여기서 문자열을 원하는 인덱스로 getData에 대한 호출로 대체합니다.

파싱 작업이 순차적으로 수행되는 것이 아니라 AST 처리 중에 필요한 노드를 찾으므로 참고할 만합니다.

이 플러그인을 실행하면 다음 코드를 얻게 됩니다.

l=~[];l={___:++l,$$$$:(![]+"")[l],__$:++l,$_$_:(![]+"")[l],_$_:++l,$_$$:({}+"")[l],$$_$:(l[l]+"")[l],_$$:++l,$$$_:(!""+"")[l],$__:++l,$_$:++l,$$__:({}+"")[l],$$_:++l,$$$:++l,$___:++l,$__$:++l};l.$_=(l.$_=l+"")[l.$_$]+(l._$=l.$_[l.__$])+(l.$$=(l.$+"")[l.__$])+((!l)+"")[l._$$]+(l.__=l.$_[l.$$_])+(l.$=(!""+"")[l.__$])+(l._=(!""+"")[l._$_])+l.$_[l.$_$]+l.__+l._$+l.$;l.$$=l.$+(!""+"")[l._$$]+l.__+l._+l.$+l.$$;l.$=(l.___)[l.$_][l.$_];l.$(l.$(l.$$+"\""+(![]+"")[l._$_]+l.$$$_+l.__+"\"+l.$__+l.___+"\"+l.__$+l.$$_+l.$$$+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$$_+l.$$$+"\"+l.__$+l.$_$+l.__$+l.$$_$+l.__+"\"+l.__$+l.$_$+l.___+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$_$+l.___+l.$$$_+"\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$__+l.$$$+"\"+l.__$+l.$_$+l.___+l.__+";\"+l.__$+l._$_+l.$$__+l._$+"\"+l.__$+l.$_$+l.$$_+"\"+l.__$+l.$$_+l._$$+l._$+(![]+"")[l._$_]+l.$$$_+".\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$_$+l.$$_+l.$$$$+l._$+"(\"+l.__$+l.$$_+l.$$$+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+");"+"\"")())();
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

결과 코드에서 볼 수 있듯이 모든 속성은 지정된 인덱스를 사용하는 getData 함수 호출로 대체되었습니다. 우리는 문자열에 대해서도 동일한 작업을 수행하고 함수 호출을 통해 문자열을 가져오기 시작했습니다. 속성 이름과 문자열 자체를 base64로 인코딩하여 눈에 띄기 어렵게 했습니다...

Here

이미 눈치채셨을 것 같습니다. 이 플러그인과 일반적인 코드에는 현 단계에서 결함이 있습니다. 예를 들어 다음 사항을 수정할 수 있습니다.

  • 속성과 문자열을 반환하는 함수는 그 목적인 getData에 대해 비명을 지르고 있습니다. 하지만 좋은 점은 식별자 이름을 바꾸는 첫 번째 플러그인을 적용하여 이 문제를 수정할 수 있다는 것입니다.
  • getData 함수 내부의 문자열 자체는 안정적으로 보호되지 않으며 base64이므로 초기 값을 찾는 것이 매우 쉽습니다. 이 문제를 해결하는 것은 더 어렵습니다. 예를 들어 getData 함수를 다시 만들고 잘 알려진 인코딩 대신 암호화를 적용할 수 있습니다.
  • getData 함수가 유일한 함수인데, 함수 자체를 끌어서 실행하면 모든 호출을 원래 값으로 대체하는 스크립트를 작성하는 것이 어렵지 않습니다.

이러한 단순성과 단점에도 불구하고 이미 난독화라고 할 수 있다고 생각합니다. 하지만 오픈 소스 난독 처리기와 유사한 작업을 수행하므로 우리는 어떻게 다릅니까?

우리는 원래 문제를 기억해야 합니다. 이러한 난독화는 공개 난독화 도구에게는 아주 쉬운 일이었습니다. 이제 우리가 얻은 코드를 가져와서 webcrack에서 난독화해 보겠습니다! (아직도 우리의 주문을 다룰 수 없기를 바랍니다.) 실질적인 중요성이 달성되었다고 말할 수 있을 것 같습니다. 우리의 "보호된" 코드는 더 이상 공개 난독화 도구를 통해 한 번의 클릭으로 되돌릴 수 없습니다

보너스. 난독화 해제

이제 새로운 주문을 배워 보겠습니다. 공개 난독화 도구는 우리 플러그인을 처리할 수 없지만 난독화의 실제 개념을 연구한 결과 소스 코드를 복원하는 데 사용할 수 있는 몇 가지 패턴을 발견할 수 있습니다.

자세히 알아보고 다음을 구체적으로 활용해 보세요.

  • 속성과 문자열을 저장하는 단일 호출 함수가 있습니다.
  • 이 함수에 대한 호출은 마스크되지 않습니다.

이러한 단점을 고려하여 다음 플러그인을 구현할 수 있습니다.

let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이 난독화 플러그인의 기능을 설명해 보겠습니다.

  1. 난독화된 코드에서 getData 함수를 복사했으며, 필수 인수(인덱스)와 함께 실행하여 필수 문자열을 얻을 수 있습니다.
  2. 모든 getData 함수 호출을 검토하고 이를 실행 결과로 대체했습니다.
  3. 마지막으로 AST에서 getData 함수를 찾아 더 이상 필요하지 않으므로 코드에서 제거했습니다.

결과적으로 다음 코드를 얻습니다.

l=~[];l={___:++l,$$$$:(![]+"")[l],__$:++l,$_$_:(![]+"")[l],_$_:++l,$_$$:({}+"")[l],$$_$:(l[l]+"")[l],_$$:++l,$$$_:(!""+"")[l],$__:++l,$_$:++l,$$__:({}+"")[l],$$_:++l,$$$:++l,$___:++l,$__$:++l};l.$_=(l.$_=l+"")[l.$_$]+(l._$=l.$_[l.__$])+(l.$$=(l.$+"")[l.__$])+((!l)+"")[l._$$]+(l.__=l.$_[l.$$_])+(l.$=(!""+"")[l.__$])+(l._=(!""+"")[l._$_])+l.$_[l.$_$]+l.__+l._$+l.$;l.$$=l.$+(!""+"")[l._$$]+l.__+l._+l.$+l.$$;l.$=(l.___)[l.$_][l.$_];l.$(l.$(l.$$+"\""+(![]+"")[l._$_]+l.$$$_+l.__+"\"+l.$__+l.___+"\"+l.__$+l.$$_+l.$$$+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$$_+l.$$$+"\"+l.__$+l.$_$+l.__$+l.$$_$+l.__+"\"+l.__$+l.$_$+l.___+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$_$+l.___+l.$$$_+"\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$__+l.$$$+"\"+l.__$+l.$_$+l.___+l.__+";\"+l.__$+l._$_+l.$$__+l._$+"\"+l.__$+l.$_$+l.$$_+"\"+l.__$+l.$$_+l._$$+l._$+(![]+"")[l._$_]+l.$$$_+".\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$_$+l.$$_+l.$$$$+l._$+"(\"+l.__$+l.$$_+l.$$$+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+");"+"\"")())();
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

Here

그래서 우리는 표시된 단점을 활용하여 babel에 대한 간단한 플러그인을 작성하여 속성과 문자열을 숨기는 난독화를 제거할 수 있었습니다.

이 작은 예를 통해 babel의 도움으로 이러한 귀찮은 일에 대처할 수 있는 방법을 설명할 수 있기를 바랍니다. 이러한 접근 방식을 사용하면 더 복잡한 난독화를 해결할 수도 있습니다. 가장 중요한 것은 코드에서 패턴을 찾고 AST를 능숙하게 작동하는 것입니다.

결론

코드 리버스 엔지니어링을 복잡하게 만드는 기술인 난독화와 이를 구현하는 도구에 대해 알아봤습니다. JavaScript 코드를 난독화하는 공개 솔루션이 있지만 즉시 이러한 보호 기능을 제거할 수 있는 공개 솔루션도 많이 있습니다.

따라서 공개 난독화 도구로 제거할 수 없는 코드를 보호하기 위한 솔루션을 직접 작성해야 합니다. JS에서 난독화를 구현하는 신뢰할 수 있는 방법 중 하나는 원하는 코드의 AST와 상호 작용하는 사용자 정의 바벨 플러그인을 작성하여 이를 읽기 어려운 형식으로 바꾸는 것입니다.

물론 이 영역에는 난독화에 대한 알려진 기술과 접근 방식이 있지만 그럼에도 불구하고 잠재적으로 코드 학습을 더 어렵게 만들 수 있는 창의성과 새로운 "트릭"이 여전히 열려 있습니다. 이러한 기술이 많이 있음에도 불구하고 코드는 항상 클라이언트의 "손에" 있기 때문에 알고리즘의 비밀성을 전혀 보장하지 않습니다. 게다가 디버깅이 가능해 코드를 더 쉽게 연구할 수 있습니다. 난독화를 사용하면 의욕이 부족한 연구자를 오히려 외면하게 되어 리버스 엔지니어링 비용이 증가합니다.

몇 가지 고급 접근 방식이 있습니다. 예를 들어 난독화 중 하나는 코드 가상화입니다. 간단히 말해서 JS에서 사용자 정의 바이트코드를 실행할 가상 머신을 생성하는 것입니다. 이 접근 방식은 정적 분석 가능성을 거의 완전히 제거하고 디버깅을 최대한 어렵게 만듭니다. 그런데 이건 별개의 논제인가요?....

이 주제에 대한 정보를 얻는 것이 도움이 되었기를 바랍니다. 처음에 난독화된 코드에 대해 더 이상 자신이나 프로그래머를 비난하지 마세요. 이 마법사들에게 감사드립니다 ??‍♀️! 여기에서 마술의 최신 트렌드에 대해 토론하게 되어 기쁩니다.

위 내용은 실험실을 번거롭게 하지 않고 JavaScript로 난독화를 만드는 방법은 다음과 같습니다: AST, Babel, 플러그인.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿