Last active
December 21, 2017 13:14
-
-
Save ufcpp/5ef97fc49eb9c0d2412377e9ef566b86 to your computer and use it in GitHub Desktop.
セキュリティホール作るのに unsafe なんて要らなかった
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Runtime.InteropServices; | |
class Base { } | |
class Derived : Base | |
{ | |
// 1個や2個だと「たまたま0詰め」な領域を指すかもしれないので無駄にたくさんフィールド並べる | |
public long A { get; } | |
public long B { get; } | |
public long C { get; } | |
public long D { get; } | |
public (long, long, long, long) T => (A, B, C, D); | |
} | |
[StructLayout(LayoutKind.Explicit)] | |
struct Union | |
{ | |
[FieldOffset(0)] | |
public Base Base; | |
[FieldOffset(0)] | |
public Derived Derived; | |
} | |
class Program | |
{ | |
// 本来やってはいけないダウンキャスト | |
static Derived AsDerived(Base b) | |
{ | |
var u = new Union(); | |
u.Base = b; | |
return u.Derived; | |
} | |
static void Main() | |
{ | |
var b = new Base(); | |
// やってはいけないダウンキャストを強行 | |
var d = AsDerived(b); | |
// Derived な変数に Base が入ってる | |
Console.WriteLine(d.GetType()); | |
// Derived にしかないはずのメンバーを読み出し | |
// (0, 0, 140708363800272, 0) みたいな身に覚えのない値が取れる | |
// 読めるだけならいいけど書き換えもできるんでさらにまずい(GC クラッシュ & セキュリティ ホール) | |
Console.WriteLine(d.T); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Runtime.InteropServices; | |
// 本来、こういう参照型と値型が混ざった Union は作れない | |
// これは、この型を使おうとした時点で TypeLoadException を起こすので実現不可 | |
// (ならコンパイル エラーにしろよという話は置いておいて) | |
[StructLayout(LayoutKind.Explicit)] | |
struct InvalidUnion | |
{ | |
[FieldOffset(0)] | |
public object Obj; | |
[FieldOffset(0)] | |
public IntPtr Ptr; | |
} | |
// が、こうやって1段クラスを挟めば… | |
class A { public object Obj; } | |
class B { public IntPtr Ptr; } | |
// 重ねても平気! | |
[StructLayout(LayoutKind.Explicit)] | |
struct ValidUnion | |
{ | |
[FieldOffset(0)] | |
public A A; | |
[FieldOffset(0)] | |
public B B; | |
} | |
class Program | |
{ | |
// 本来やってはいけない無関係な型へのキャスト | |
static B Cast(A a) | |
{ | |
var u = new ValidUnion(); | |
u.A = a; | |
return u.B; | |
} | |
static void Main() | |
{ | |
var a = new A { Obj = "abc" }; | |
// やってはいけないキャストを強行 | |
var b = Cast(a); | |
// a.Obj のアドレスが取れる | |
// ちなみに、GC 管理下のメモリのアドレスを取るのとか、 | |
// safe な範囲どころか、unsafe を使ってもなかなか取るの難しい邪悪な所業 | |
// もちろん、書き換えたら GC クラッシュの原因 | |
Console.WriteLine(b.Ptr); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment