2017-12-29 3 views
1

.NET 응용 프로그램은 어셈블리이라는 파일에 배포되며 메타 데이터 및 CIL (Common Intermediate Language) 코드가 포함되어 있습니다. 이 표준을 준수하는 경우확인할 수없는 .NET 어셈블리가 유효하도록하려면 어떻게해야합니까?

  • 어셈블리가 유효입니다 : .NET이 준수 표준, ECMA-335, II.3는 두 개의 유사한 소리가 나는 용어 ​​사이의 구별을 말한다.

    유효성 검사는 파일 형식, 메타 데이터 및 CIL이 자체 일관성이 있는지 확인하기 위해 모든 파일에서 테스트 집합을 적용하는 것을 의미합니다. 이 테스트는 파일이이 사양의 표준 요구 사항을 준수하는지 확인하기위한 것입니다. 어셈블리 형태 보증 즉, 표준 기술 정적 분석 알고리즘을 통해 조립이 유효하고 검증 할 수 있다면

  • 어셈블리는 검증이다.

    확인은 CIL 코드 시퀀스가 ​​프로그램의 논리 주소 공간 외부의 메모리에 대한 액세스를 허용하지 않도록 CIL과 관련 메타 데이터를 검사하는 것을 말합니다. 유효성 검사 테스트와 함께 검증을 통해 프로그램에서 메모리 또는 액세스 권한이 부여되지 않은 다른 리소스에 액세스 할 수 없도록 보장합니다.

모든 검증 어셈블리는 유효하지만, 모든 유효한 어셈블리 검증 있습니다. 또한 일부 유효한 어셈블리는 실제로는 형식에 안전 할 수 있지만 확인 알고리즘으로는이를 증명할 수 없으므로 검증 할 수 없습니다. 표준에서 다이어그램을 사용하려면 PEVerify :

ECMA-335, II.3, Figure 1: Relationship between correct and verifiable CIL

닷넷 SDK 어셈블리가 검증 경우 정적으로 결정하는 도구를 제공합니다. 확인 가능한 어셈블리도 유효해야하므로이 도구는 어셈블리가 유효하지 않은 경우 오류를보고합니다.

그러나 조립품이 인지 여부는이 맞는지 확인하는 것과 동등한 도구 또는 절차가없는 것으로 보입니다. 예를 들어, 어셈블리를 확인할 수 없다는 것을 이미 알았 으면 좋겠다. 그래도 괜찮 으면, 런타임에서 유효하지 않은 프로그램으로 인해 오류가 발생하지 않도록하려면 어떻게해야합니까??

내 테스트 케이스 :

.assembly extern mscorlib 
{ 
    .publickeytoken = (B7 7A 5C 56 19 34 E0 89) 
    .ver 4:0:0:0 
} 

.assembly MyAsm { } 
.module MyAsm.exe 
.corflags 0x00020003 // ILONLY 32BITPREFERRED 

.class public Program 
{ 
    .method public static int32 EntryPoint(string[] args) cil managed 
    { 
    .maxstack 2 
    .entrypoint 

    call string [MyAsm]Program::normal() 
    call void [mscorlib]System.Console::WriteLine(string) 

    call string [MyAsm]Program::unverifiable_init() 
    call void [mscorlib]System.Console::WriteLine(string) 

    call string [MyAsm]Program::unverifiable_jmp() 
    call void [mscorlib]System.Console::WriteLine(string) 

    call string [MyAsm]Program::invalid() 
    call void [mscorlib]System.Console::WriteLine(string) 

    ldc.i4.0 
    ret 
    } 

    .method public static string normal() cil managed 
    { 
    .maxstack 2 
    .locals init ([0] int32 initialized) 

    ldstr "From normal: " 
    ldloca initialized 
    call instance string [mscorlib]System.Int32::ToString() 
    call string [mscorlib]System.String::Concat(string, string) 

    ret 
    } 

    .method public static string unverifiable_jmp() cil managed 
    { 
    .maxstack 1 

    ldstr "Printing from unverifiable_jmp!" 
    call void [mscorlib]System.Console::WriteLine(string) 

    jmp string [MyAsm]Program::normal() // jmp is always unverifiable 
    } 

    .method public static string unverifiable_init() cil managed 
    { 
    .maxstack 2 
    .locals ([0] int32 hasGarbage) // uninitialized locals are unverifiable 

    ldstr "From unverifiable_init: " 
    ldloca hasGarbage 
    call instance string [mscorlib]System.Int32::ToString() 
    call string [mscorlib]System.String::Concat(string, string) 

    ret 
    } 

    .method public static string invalid() cil managed 
    { 
    .maxstack 1 

    ldstr "Printing from invalid!" 
    call void [mscorlib]System.Console::WriteLine(string) 

    ldstr "From invalid" 
    // method fall-through (no ret) is invalid 
    } 
} 

나는이 MyAsm.exe을 생산, ilasm를 사용하여 조립한다.

어셈블리를 실행할 수 있지만 어셈블리를로드 할 때가 아니라 invalid() 메서드를 호출하면 .NET 런타임에서 오류가 발생합니다. 호출을 제거하면 오류없이 프로그램이 완료까지 실행되므로 어셈블리를로드하고 실행한다고해서 이것이 완전히 유효하다는 보장은 없습니다.

어셈블리에서 PEVerify를 실행하면 세 가지 오류가 발생합니다.인간의 눈에는 처음 두 개의 오류가 확인 오류이며 마지막 하나는 유효성 검사 오류이며, 차별화를 자동화하는 쉬운 방법은없는 것처럼 보입니다 (예 : 에 대한 각 행을 확인하는 것은 너무 광범위하게 보입니다.) @Damien_The_Unbelievers을 바탕으로

Microsoft (R) .NET Framework PE Verifier. Version 4.0.30319.0 
Copyright (c) Microsoft Corporation. All rights reserved. 

[IL]: Error: [C:\...\MyAsm.exe : Program::unverifiable_jmp][offset 0x0000000A] Instruction cannot be verified. 
[IL]: Error: [C:\...\MyAsm.exe : Program::unverifiable_init][offset 0x00000005] initlocals must be set for verifiable methods with one or more local variables. 
[IL]: Error: [C:\...\MyAsm.exe : Program::invalid][offset 0x0000000A] fall through end of the method without returning 
3 Error(s) Verifying MyAsm.exe 
+0

나쁜 생각 번호 1 - 여기 *'ngen'을 남용 할 수 있다고 생각합니다. 모든 메소드를 컴파일해야하기 때문에 무효 메소드에 대해 어떤 종류의 오류가 발생해야합니다. 나는 그 안에 내장 된 다른 것을 생각할 수 없다. 어셈블리의 모든 메소드가 강제로 JIT되도록하십시오. –

+0

@Damien_The_Unbeliever 나는 이것을 시도하고 그것이 효과가있는 것으로 보인다. 'ngen install MyAsm.exe'는 검증 성이 아니라 유효성만을위한 오류를보고합니다 ('Common Language Runtime은 프로그램 Program.invalid를 컴파일하는 동안 유효하지 않은 프로그램을 발견했습니다.). 이상하게도 이것은 여전히 ​​코드 0으로 끝나고, 나중에'ngen display MyAsm.exe'를 사용할 수 있습니다. (이 호출은 -1로 끝납니다.)'install'을 다시 호출하기 전에'ngen uninstall MyAsm.exe'를 사용해야합니다. 그래서 그것은 AOT 컴파일 오류에도 불구하고 설치되어있을 것 같아? 어쨌든이 질문을 대답으로 제출할 수 있다고 생각합니다. –

+0

나는 그것을 이유로 답변을 제출하지 않았다. 결과를 얻기 위해 인프라를 심각하게 악용하고있다. thehennyy는 사용하기에 덜 "오염 될"것 같은 어떤 종류의 대답을 제공 한 것 같습니다. 일반적으로 유효성 오류를 얻기 위해 어딘가에 컴파일을 유발해야하고 검색 도구 (유효성 만 검사하고 확인하지 않음)는 필요하지 않습니다. –

답변

3

나는 각각의 방법을 컴파일하려면 RuntimeHelpers.PrepareMethod Method를 사용하는이 작은 조각을 썼다 언급. 그것은 모든 경우 (중첩 된 유형, 제네릭, 참조 해상도, ...)를 처리하지 않습니다하지만 출발점으로 작동 :

var b = File.ReadAllBytes("MyAsm.exe"); 
var asm = Assembly.Load(b); 

foreach(var m in asm.GetModules()) 
{ 
    foreach(var t in m.GetTypes()) 
    { 
     foreach(var mb in t.GetMethods((BindingFlags)62).Cast<MethodBase>().Union(t.GetConstructors((BindingFlags)62))) 
     { 
      try 
      { 
       RuntimeHelpers.PrepareMethod(mb.MethodHandle); 
      } 
      catch (InvalidProgramException ex) 
      { 
       Console.WriteLine($"{mb.DeclaringType}::{mb.Name} - {ex.Message}"); 
      } 

     } 
    } 
} 

출력됩니다 :

프로그램 :: 무효를 - 공통 언어 런타임에서 유효하지 않은 프로그램을 발견했습니다.

+0

고마워요. 만약 누군가가 이것을 재현하려한다면 두 개의 주석이 필요합니다 : (1)'(BindingFlags) 62'는'DeclaredOnly','Instance','Static','Public','NonPublic' 플래그의 조합입니다. (2)'PrepareMethod' 호출은 어셈블리가이 프로그램 어셈블리와 같은 디렉토리에 있어야합니다. –

+0

궁금한 점은 일반적인 메소드도 처리하는 것이 얼마나 힘들겠습니까? – IllidanS4

+0

@ IllidanS4 두 가지 옵션이 있습니다 : ILReader를 사용하여 모든 발생 인스턴스화를 처리하고 나중에 제약 조건을 충족하는 "임의"유형을 사용하십시오. 일반 메소드의 유효성은 일반 매개 변수에 의존하지 않아야하므로 이후 접근법으로 충분할 수 있습니다. – thehennyy

관련 문제