UFO ET IT

System.String.Empty를 덮어 쓰도록 Reflection API에 요청하는 의미는 무엇입니까?

ufoet 2020. 11. 30. 20:26
반응형

System.String.Empty를 덮어 쓰도록 Reflection API에 요청하는 의미는 무엇입니까?


이 코드를 우연히 발견했습니다.

static void Main()
{
    typeof(string).GetField("Empty").SetValue(null, "evil");//from DailyWTF

    Console.WriteLine(String.Empty);//check

    //how does it behave?
    if ("evil" == String.Empty) Console.WriteLine("equal"); 

    //output: 
    //evil 
    //equal

 }

이 코드를 어떻게 컴파일 할 수 있는지 궁금합니다. 내 추론은 :

MSDN에 따르면 String.Empty읽기 전용이므로 변경이 불가능해야하며 컴파일은 "정적 읽기 전용 필드를 할당 할 수 없습니다"또는 유사한 오류로 끝나야합니다.

나는 Base Class Library 어셈블리가 어떻게 든 보호되고 서명되어 있으며 정확히 이러한 종류의 공격을 막을 수 없다고 생각했습니다. 다음에 누군가 System.Security.Cryptography 또는 다른 중요한 클래스를 변경할 수 있습니다.

.NET 설치 후 기본 클래스 라이브러리 어셈블리가 NGEN에 의해 ​​컴파일되므로 String 클래스의 필드를 변경하려면 고급 해킹이 필요하고 훨씬 더 어렵습니다.

그러나이 코드는 컴파일되고 작동합니다. 누군가 내 추론에 무엇이 잘못되었는지 설명해 주시겠습니까?


정적 읽기 전용 필드를 할당 할 수 없습니다.

당신은 그것에 할당하지 않습니다. System.Reflection네임 스페이스 에서 공용 함수를 호출하고 있습니다. 컴파일러가 그것에 대해 불평 할 이유가 없습니다.

게다가, typeof(string).GetField("Empty")컴파일러가 인수 여부를 모든 경우에 이야기 할 더 확실한 방법이 없다, 대신 사용자가 입력 변수를 사용할 수 GetField있는 끝날는 "Empty".

Reflection필드가 표시 initonly되고 런타임에 오류가 발생 하는지 확인 하고 싶다고 생각합니다 . 나는 당신이 그것을 기대하는 이유를 알 수 있지만 화이트 박스 테스트의 경우 initonly필드에 쓰기에도 일부 응용 프로그램이 있습니다.

NGEN이 효과가없는 이유는 여기에서 코드를 수정하지 않고 데이터 만 수정하기 때문입니다. 데이터는 다른 언어와 마찬가지로 .NET을 사용하여 메모리에 저장됩니다. 네이티브 프로그램은 문자열 상수와 같은 것에 대해 읽기 전용 메모리 섹션을 사용할 수 있지만 문자열에 대한 포인터는 일반적으로 여전히 쓰기 가능하며 여기에서 일어나는 일입니다.

이 의심스러운 방식으로 리플렉션을 사용하려면 코드가 완전 신뢰로 실행되어야합니다. 또한 변경 사항은 하나의 프로그램에만 영향을 미치며, 생각하는 것처럼 보안 취약점이 아닙니다 (완전히 신뢰하는 프로세스 내에서 악성 코드를 실행하는 경우 설계 결정은 반사가 아니라 보안 문제임). .


또한 initonly내부 필드 의 값은 mscorlib.dll.NET 런타임의 전역 불변입니다. 이를 깨뜨린 후에는 System.String.Empty의 현재 값을 검사하는 코드도 손상 되었기 때문에 해당 고정이 손상되었는지 여부를 안정적으로 테스트 할 수 없습니다. 시스템 불변을 위반하기 시작하면 아무것도 신뢰할 수 없습니다.

.NET 사양 내에서 이러한 값을 지정하면 컴파일러가 전체 성능 최적화를 구현할 수 있습니다. 간단한 것은

s == System.String.Empty

(s != null) && (s.Length == 0)

동일하지만 후자는 훨씬 빠릅니다 (상대적으로 말하면).

또한 컴파일러는

if (int.Parse(s) > int.MaxValue)

true가 아니며 else 블록으로 무조건 점프를 생성합니다 ( Int32.Parse동일한 예외 동작을 갖기 위해 여전히 호출 해야하지만 비교를 제거 할 수 있음).

System.String.EmptyBCL 구현 내부에서도 광범위하게 사용됩니다. 덮어 쓰면 프로그램 외부에서 유출되는 손상을 포함하여 모든 종류의 미친 일이 발생할 수 있습니다 (예를 들어 문자열 조작을 사용하여 이름이 빌드 된 파일에 쓸 수 있습니다 ... 문자열이 끊어지면 잘못된 파일을 덮어 쓸 수 있습니다).


그리고 동작은 .NET 버전마다 쉽게 다를 수 있습니다. 일반적으로 새로운 최적화 기회가 발견되면 이전 버전의 JIT 컴파일러로 백 포트되지 않습니다 (그렇더라도 백 포트가 구현되기 전의 설치가있을 수 있음). 특히. String.Empty관련 최적화는 .NET 2.x와 Mono 및 .NET 4.5 이상에서 눈에 띄게 다릅니다.


코드의 모든 줄이 완벽하게 합법적 인 C #이기 때문에 코드가 컴파일됩니다. 구문 오류라고 생각하는 특정 줄은 무엇입니까? 읽기 전용 필드에 할당하는 코드 줄이 없습니다. 읽기 전용 필드에 할당하는 Reflection에서 메서드를 호출하는 코드 줄이 있지만 이미 컴파일되어 있고 궁극적으로 보안을 깨는 것은 C #으로 작성되지 않았고 C ++로 작성되었습니다. 런타임 엔진 자체의 일부입니다.

완전 신뢰는 완전 신뢰를 의미 하므로 코드가 성공적으로 실행됩니다 . 완전 신뢰 환경에서 코드를 실행하고 완전 신뢰는 완전 신뢰를 의미 하므로 런타임은이 어리석은 위험한 일을 할 때 무엇을하고 있는지 알고 있다고 가정합니다.

If you try running your code in a partially trusted environment then you'll see that Reflection throws a "you're not allowed to do that" exception.

And yes, the assemblies are signed and whatnot. If you're running fully-trust code, then sure, they can screw around with those assemblies as much as they want. That's what full trust means. Partially trusted code doesn't get to do that but fully trusted code can do anything you can do. Only grant full trust to code you actually trust to not do crazy things on your behalf.


Reflection allows you to defy laws of physics do anything. You can even set the value of private members.

Reflection does not follow rules, you can read about it on MSDN.

Another example: Can I change a private readonly field in C# using reflection?


If you are on a web application you can set the trust level of your application.

level="[Full|High|Medium|Low|Minimal]"

These are the restriction of the trust level, accondingly to MSDN, at medium trust you restrict reflection access.

Edit: DO NOT run a web application other than Full Trust, this is a direct recommendation from ASP.NET team. To protect your application create one App Pool for each website.


Also, it is not recommended to go wild using reflection for everything. It has the right place and time to be used.


A point nobody mentioned here before: This piece of code causes different behavior on different .net implementations/platforms. Actually on Mono it returns nothing at all: see IDE One (Mono 2.8), my local Mono 2.6.7 (linux) produces the same "output".

I haven't yet looked at the low level code, but I suppose it's compiler specific just as mentioned by PRASHANT P or the runtime environment.

UPDATE

Running the Mono compiled exe on Windows (MS Dotnet 4) produces

evil 
equal

Running the Windows compiled exe on linux was not possible (Dotnet 4...) so I recompiled with Dotnet 2 (it still says evil and equal on Windows). There is "no" output. Of course there must be at least the "\n" from the first WriteLine, in fact it is there. I piped the output to a file and started up my hexeditor to look at a single character 0x0A.

To cut a long story short: It seems to be runtime environment specific.


readonly is only enforce

at COMPILER level

therefore

may be changed at current beneath level

참고URL : https://stackoverflow.com/questions/6293924/what-are-the-implications-of-asking-reflection-apis-to-overwrite-system-string-e

반응형