2014-01-21 6 views
1

Red Gate Ant Profiler 또는 Reflector와 같은 도구로 IL을 C# 또는 VB.NET 코드로 변환 할 수 있습니까?리플렉터가 코드를 디 컴파일하는 방법은 무엇입니까?

최근 레드 게이트 개미 프로필러가 원래 작성된 것과 동일한 소스 코드를 생성하지 않는다는 사실에 주목했습니다.

foreach을 사용하여 while 루프를 생성했습니다.

그렇게 생각하게되었습니다. Reflector에서 Reflector.exe 자체를 열었지만 코드가 대부분 (전부는 아님) 난독 화되었습니다.

+4

귀하의 호기심을 충족시키기 위해 [ILSpy] (http://ilspy.net/)가 있으며 오픈 소스 – Steve

+0

입니다. Steve. 필자는 ILSpy와 dotPeek를 포함하여 몇 가지 소스 코드를 살펴볼 수있는 많은 것들 중에서 목록을 작성했습니다. 여기에 내가 찾은 목록이 있습니다. http://stackoverflow.com/questions/2425973/open-source-alternatives-to-reflector –

답변

7

일반적으로 디 컴파일러는 IL을보고 IL과 의미 상 동일한 소스 코드를 작성하여 작동합니다. IL은 일부 높은 수준의 정보 (기계 코드만큼은 아닐지라도)를 떨어 뜨리기 때문에 그리고 보통 같은 IL에 컴파일되는 여러 조각의 코드가 있기 때문에 이것은 항상 orignal 소스 코드를 생성 할 수 없습니다. 예를 들어, foreach 루프는 특정 종류의 while 루프와 같습니다 (열거자를 먼저 설정 한 다음 열거자를 모두 사용할 때까지 반복하고 각 단계에서 열거자를 고급).

3

디 컴파일을 구현하는 일반적인 기술은 루프의 범위를 식별하기 위해 "간격 분석"을 사용하는 것입니다.

관용구 인식과 결합 된 패턴을 "파생 된 그래프 시퀀스"라고하면 어셈블리 언어 (또는 MSIL)가 포함 된 제어 흐름 그래프로 시작하여 단일 AST (추상화)가있을 때까지 반복적으로 단순화 할 수 있습니다 (또는 방법)의 "소스 레벨 (source level)"뷰를 나타내는 노드 (예를 들어, 구문 트리) 노드를 포함 할 수있다. AST를 감안할 때 출처를 생성하는 것은 간단합니다. 그 다음에 결과 AST를 인쇄합니다. 여기

자세한 내용은 몇 가지 링크입니다 :

http://en.wikipedia.org/wiki/Interval_(graph_theory)

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.50.8004&rep=rep1&type=pdf

일반적으로, 원본 소스와 디 컴파일 소스 사이의 완전하고 성실하게이 없을거야.

foreach 루프의 제어 흐름 그래프는 while 루프의 제어 흐름 그래프와 유사합니다. 이는 주로 다음과 같은 코드로 인해 :

foreach (var x in xs) { 
    //body 
} 

가 실제로 문법 설탕이다는 foreach 루프는 기본적으로 while 루프로 번역 된 다음 while 루프가로 컴파일

var enumerator = xs.GetEnumerator() 
try { 
    while (enumerator.MoveNext()) { 
     var x = xs.Current; 
     //body 
    } 
} 
finally { 
    enumerator.dispose(); 
} 

MSIL.

디 컴파일러가 for-each 루프를 생성하려면 while 루프가 실제로 foreach 루프 일 때를 추측하려는 특수 지원을 추가해야합니다. 그러한 논리가 완벽하지는 않습니다 (위의 while 루프와 foreach 루프 모두 동일한 (또는 매우 유사한) MSIL 코드를 생성해야합니다).

경우에 따라 작성한 소스와 일치하고 다른 경우에는 그렇지 않을 수도 있습니다.

for-each 루프를 작성할 가능성이 높습니다. 유용성의 관점에서 볼 때 for-each 루프 대 while 루프가 좋은 선택입니다.

그러나 추가 작업입니다. 디 컴파일러 작성자는 "각 루프를 감지하려고하는 경험적 방법을 추가하고 싶다"고 말하며 설정해야합니다.

마지막으로 디 컴파일을 방해 할 수있는 많은 것들이 있습니다. 예를 들어 "break"및 "continue"문이 있으면 실제로 상황이 복잡해질 수 있습니다. 특정 종류의 중첩 (switch 문 내부의 루프 및 그 반대로)이 가능합니다. 그들은 모두 하나 이상의 진입 점과 하나 이상의 이탈 점을 갖는 CFG 루프로 이어질 수 있습니다. 이렇게하면 읽을 수있는 소스 코드를 생성하기가 어려워집니다.

일반적으로 이러한 경우를 처리하는 유일한 방법은 경험적 방법을 사용하는 것입니다. 그 경험적 방법은 때때로 "잘못된 일을 할 것"입니다.

또한 루프 경계에 사용되는 특정 표현식과 같은 사소한 것들도 관용어 인식을 손상시킬 수 있습니다. 때때로 컴파일러는 (소스에없는) 임시 변수를 도입 할 것입니다. 이것은 관용 검사를 추가하거나 데이터 흐름 분석 (라이브 변수 분석, 정의 사용 체인 등)과 같은 고급 기법을 필요로 할 수 있습니다.

요약 : 디 컴파일은 어렵고 결코 완벽하지 않습니다. 또한, 구현자는 트레이드 오프를 고려해야한다고 확신합니다. 예를 들어, for each loops를 탐지하는 데 투자하거나 Lambda를 디 컴파일하고 LINQ 쿼리를 추론하는 데 시간을 할애해야합니까?