문제

기본 X86 Binaries를 디 컴파일하는 것과 비교하여 .NET IL 코드를 소스 코드로 디 컴파일하는 것이 왜 그렇게 쉬운가요? (반사판은 대부분의 시간에 상당히 좋은 소스 코드를 생성하지만 C ++ 컴파일러의 출력을 디 컴파일하는 것은 거의 불가능합니다.)

IL에 많은 메타 데이터가 포함되어 있기 때문입니까? 아니면 IL이 x86 지침보다 높은 추상화이기 때문입니까? 나는 약간의 연구를했고 다음 두 가지 유용한 기사를 발견했지만 그 중 어느 것도 내 질문에 대답하지 않았습니다.

도움이 되었습니까?

해결책

나는 당신이 이미 가장 중요한 비트를 가지고 있다고 생각합니다.

  • 당신이 말했듯이, 더 많은 메타 데이터를 사용할 수 있습니다. C 또는 C ++ 컴파일러가 방출 한 내용에 대한 세부 사항을 모르겠지만 멀리 더 많은 이름과 유사한 정보가 IL에 포함되어 있습니다. 예를 들어 X86과 관련하여 특정 스택 프레임의 내용에 대해 디 컴파일러가 알고있는 내용을 살펴보십시오. 스택이 어떻게되는지 알 수 있습니다. 사용된 ; IL에서는 스택의 내용이 무엇인지 알고 있습니다. 대표하다 (또는 적어도, 의미 론적 의미가 아닙니다!)
  • 다시 언급했듯이 IL은 X86보다 높은 수준의 추상화입니다. X86은 메소드 또는 함수 호출이 무엇인지, 이벤트 또는 속성 등이 무엇인지 전혀 모릅니다.
  • 일반적으로 C 및 C ++ 컴파일러는 C# 컴파일러보다 훨씬 더 많이 최적화됩니다. C# 컴파일러는 대부분의 최적화가 JIT에 의해 나중에 여전히 수행 될 수 있다고 가정하기 때문입니다. 어떤면에서는 C# 컴파일러에 적합합니다. ~ 아니다 C# 컴파일러는 JIT에 사용할 수있는 다양한 정보가 있기 때문에 많은 최적화를 시도합니다. 최적화 된 코드는 원래 소스 코드를 자연스럽게 표현하지 못하기 때문에 디 컴파일하기가 어렵습니다.
  • IL은 JIT 컴파일되도록 설계되었습니다. X86은 기본적으로 실행되도록 설계되었습니다 (마이크로 코드를 통해). JIT 컴파일러에 필요한 정보는 디 컴파일러가 원하는 것과 유사하므로 디 컴파일러는 IL에서 더 쉬운 시간을 갖습니다. 어떤면에서 이것은 실제로 두 번째 요점의 재조정 일뿐입니다.

다른 팁

리버스 엔지니어링 IL을 상당히 쉽게 만드는 데 많은 것들이 있습니다.

  • 유형 정보. 이것은 방대합니다. x86 어셈블러에서는 사용 방법에 따라 변수의 유형을 추론해야합니다.

  • 구조. 응용 프로그램의 구조에 대한 정보는 IL 분해에서 더 많이 사용할 수 있습니다. 이것은 유형 정보와 결합하여 놀라운 양의 데이터를 제공합니다. 이 시점에서 꽤 높은 수준에서 일하고 있습니다 (x86 어셈블러와 관련하여). 기본 어셈블러에서는 데이터 사용 방식에 따라 구조 레이아웃 (구조라는 사실)을 추론해야합니다. 불가능하지는 않지만 훨씬 더 많은 시간이 소요됩니다.

  • 이름. 사물의 이름을 아는 것이 유용 할 수 있습니다.

이러한 것들이 결합 된 것은 실행 파일에 대한 많은 데이터가 있음을 의미합니다. IL은 기본적으로 기본 코드의 컴파일러보다 소스에 훨씬 더 가까운 레벨에서 작동합니다. 바이트 코드가 작동하는 수준이 높을수록 리버스 엔지니어링이 쉽고 일반적으로 말하면됩니다.

C#과 IL은 거의 일대일로 거의 매핑됩니다. (이것은 일부 새로운 C# 3.0 기능에서는 적습니다.) 매핑의 근접성 (및 C# 컴파일러의 최적화 부족)은 물건을 '가역적'으로 만듭니다.

브라이언의 정답 확장

모든 IL이 쉽게 분해 될 수 있다고 생각되면 사소한 F# 프로그램을 작성하고 해당 코드를 디 컴파일하려고 시도하는 것이 좋습니다. F#은 많은 코드 변환을 수행하므로 실제 방출 된 IL 및 원래 코드베이스의 매핑이 매우 열악합니다. IMHO, Decompiled F# 코드를보고 C# 또는 VB.NET보다 원래 프로그램을 되 찾는 것이 훨씬 더 어렵습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top