4 import KernelCollection
 
   6 # This is the same as auxkc-pageablekc-vtable-patching-namespaces 
   7 # but this test has all local symbols instead of global symbols 
  10 # The kernel has class OSObject and subclass KernelClass 
  11 # foo.kext sublclasses KernelClass to get Foo1, and subclasses that to get Foo2 
  12 # bar.kext sublclasses Foo1 to get Bar1, and subclasses that to get Bar2 
  14 # In KernelClass the vtable layout is: 
  15 # [ ..., foo() kernelClassUsed0() ] 
  17 # In Foo1, the layout is: 
  18 # [ ..., foo() kernelClass_RESERVED0(), foo1Used0(), foo1Used1() ] 
  20 # In Foo2, the layout is: 
  21 # [ ..., foo() kernelClass_RESERVED0(), foo1Used0(), foo1_RESERVED1(), foo1_RESERVED2(), foo1_RESERVED3() ] 
  23 # In Bar1, the layout is: 
  24 # [ ..., foo() kernelClass_RESERVED0(), foo1Used0(), foo1_RESERVED1(), foo1_RESERVED2(), foo1_RESERVED3() ] 
  26 # In Bar2, the layout is: 
  27 # [ ..., foo() kernelClass_RESERVED0(), foo1Used0(), foo1_RESERVED1(), foo1_RESERVED2(), foo1_RESERVED3() ] 
  29 # All kext's will end up getting the vtable entry after foo() patched to kernelClassUsed0() 
  30 # Foo2, Bar1, Bar2, will also get the vtable entry after foo1Used0() patched to foo1Used1() 
  32 def findGlobalSymbolVMAddr(kernel_cache
, dylib_index
, symbol_name
): 
  33     for symbol_and_addr 
in kernel_cache
.dictionary()["dylibs"][dylib_index
]["global-symbols"]: 
  34         if symbol_and_addr
["name"] == symbol_name
: 
  35             return symbol_and_addr
["vmAddr"] 
  38 def findLocalSymbolVMAddr(kernel_cache
, dylib_index
, symbol_name
): 
  39     for symbol_and_addr 
in kernel_cache
.dictionary()["dylibs"][dylib_index
]["local-symbols"]: 
  40         if symbol_and_addr
["name"] == symbol_name
: 
  41             return symbol_and_addr
["vmAddr"] 
  44 def findFixupVMAddr(kernel_cache
, fixup_name
): 
  45     for fixup_vmaddr
, fixup_target 
in kernel_cache
.dictionary()["fixups"].iteritems(): 
  46         if fixup_target 
== fixup_name
: 
  50 def findPagableFixupVMAddr(kernel_cache
, dylib_index
, fixup_name
): 
  51     for fixup_vmaddr
, fixup_target 
in kernel_cache
.dictionary()["dylibs"][dylib_index
]["fixups"].iteritems(): 
  52         if fixup_target 
== fixup_name
: 
  56 def findAuxFixupVMAddr(kernel_cache
, dylib_index
, fixup_name
): 
  57     for fixup_vmaddr
, fixup_target 
in kernel_cache
.dictionary()["dylibs"][dylib_index
]["fixups"].iteritems(): 
  58         if fixup_target 
== fixup_name
: 
  62 def offsetVMAddr(vmAddr
, offset
): 
  63     het_int 
= int(vmAddr
, 16) 
  64     het_int 
= het_int 
+ offset
 
  65     return ''.join([ '0x', hex(het_int
).upper()[2:] ]) 
  67 def check(kernel_cache
): 
  69     kernel_cache
.buildKernelCollection("x86_64", "/auxkc-pageablekc-vtable-patching-namespaces-locals/main.kc", "/auxkc-pageablekc-vtable-patching-namespaces-locals/main.kernel", "", [], []) 
  70     kernel_cache
.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/main.kc", ["-layout", "-arch", "x86_64"]) 
  72     assert len(kernel_cache
.dictionary()["dylibs"]) == 1 
  73     assert kernel_cache
.dictionary()["dylibs"][0]["name"] == "com.apple.kernel" 
  75     # Get the addresses for the symbols we are looking at.  This will make it easier to work out the fixup slots 
  76     kernel_cache
.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/main.kc", ["-symbols", "-arch", "x86_64"]) 
  78     # From kernel, we want to know where the vtable is, and the foo() and kernelClassUsed0() slots in that vtable 
  80     kernelClassFooVMAddr 
= findGlobalSymbolVMAddr(kernel_cache
, 0, "__ZN1X11KernelClass3fooEv") 
  82         print "kernelClassFooVMAddr: " + kernelClassFooVMAddr
 
  84     # KernelClass::kernelClassUsed0() 
  85     kernelClassUsed0VMAddr 
= findGlobalSymbolVMAddr(kernel_cache
, 0, "__ZN1X11KernelClass16kernelClassUsed0Ev") 
  87         print "kernelClassUsed0VMAddr: " + kernelClassUsed0VMAddr
 
  91     kernel_cache
.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/main.kc", ["-fixups", "-arch", "x86_64"]) 
  93     # In vtable for Foo, we match the entry for Foo::foo() by looking for its value on the RHS of the fixup 
  94     kernelFooFixupAddr 
= findFixupVMAddr(kernel_cache
, "kc(0) + " + kernelClassFooVMAddr 
+ " : pointer64") 
  96         print "kernelFooFixupAddr: " + kernelFooFixupAddr
 
  97     # Then the following fixup should be to KernelClass::kernelClassUsed0() 
  98     kernelFooNextFixupAddr 
= offsetVMAddr(kernelFooFixupAddr
, 8) 
 100         print "kernelFooNextFixupAddr: " + kernelFooNextFixupAddr
 
 101     assert kernel_cache
.dictionary()["fixups"][kernelFooNextFixupAddr
] == "kc(0) + " + kernelClassUsed0VMAddr 
+ " : pointer64" 
 103     # From this point on, the vmAddr for __ZN1X11KernelClass16kernelClassUsed0Ev is an offset in to kc(0) 
 104     # so we want to turn it from a vmAddr to vmOffset by subtracting the base address of 0x4000 which is on __HIB 
 105     kernelClassUsed0VMOffset 
= offsetVMAddr(kernelClassUsed0VMAddr
, -0x4000) 
 107         print "kernelClassUsed0VMOffset: " + kernelClassUsed0VMOffset
 
 109     # ----------------------------------------------------------- 
 110     # Now build an pageable cache using the baseline kernel collection 
 111     kernel_cache
.buildPageableKernelCollection("x86_64", "/auxkc-pageablekc-vtable-patching-namespaces-locals/pageable.kc", "/auxkc-pageablekc-vtable-patching-namespaces-locals/main.kc", "/auxkc-pageablekc-vtable-patching-namespaces-locals/extensions", ["com.apple.foo1", "com.apple.foo2"], []) 
 112     kernel_cache
.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/pageable.kc", ["-layout", "-arch", "x86_64"]) 
 114     assert len(kernel_cache
.dictionary()["dylibs"]) == 2 
 115     assert kernel_cache
.dictionary()["dylibs"][0]["name"] == "com.apple.foo1" 
 116     assert kernel_cache
.dictionary()["dylibs"][1]["name"] == "com.apple.foo2" 
 119     # Get the addresses for the symbols we are looking at.  This will make it easier to work out the fixup slots 
 120     kernel_cache
.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/pageable.kc", ["-symbols", "-arch", "x86_64"]) 
 122     # From foo1, find the vtable and its override of foo() 
 124     pageableFoo1FooVMAddr 
= findLocalSymbolVMAddr(kernel_cache
, 0, "__ZN1X4Foo13fooEv") 
 126         print "pageableFoo1FooVMAddr: " + pageableFoo1FooVMAddr
 
 128     pageableFoo1FooUsed0VMAddr 
= findLocalSymbolVMAddr(kernel_cache
, 0, "__ZN1X4Foo19foo1Used0Ev") 
 130         print "pageableFoo1FooUsed0VMAddr: " + pageableFoo1FooUsed0VMAddr
 
 132     pageableFoo1FooUsed1VMAddr 
= findLocalSymbolVMAddr(kernel_cache
, 0, "__ZN1X4Foo19foo1Used1Ev") 
 134         print "pageableFoo1FooUsed1VMAddr: " + pageableFoo1FooUsed1VMAddr
 
 136     # From foo2, find the vtable and its override of foo() 
 138     pageableFoo2FooVMAddr 
= findLocalSymbolVMAddr(kernel_cache
, 1, "__ZN1X4Foo23fooEv") 
 140         print "pageableFoo2FooVMAddr: " + pageableFoo2FooVMAddr
 
 141     # Also find Foo2::foo1Used0() as it overrides foo1Used0 from the superclass 
 142     pageableFoo2FooUsed0VMAddr 
= findLocalSymbolVMAddr(kernel_cache
, 1, "__ZN1X4Foo29foo1Used0Ev") 
 144         print "pageableFoo2FooUsed0VMAddr: " + pageableFoo2FooUsed0VMAddr
 
 148     kernel_cache
.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/pageable.kc", ["-fixups", "-arch", "x86_64"]) 
 149     kernel_cache
.dictionary()["fixups"] == "none" 
 152     # The vtable we have is [ ..., foo(), kernelClass_RESERVED0(), foo1Used0(), foo1Used1() ] 
 153     # and we want           [ ..., foo(), kernelClassUsed0(),      foo1Used0(), foo1Used1() ] 
 155     # In vtable for Foo1, we match the entry for Foo1::foo() by looking for its value on the RHS of the fixup 
 156     pageableFoo1FooFixupAddr 
= findPagableFixupVMAddr(kernel_cache
, 0, "kc(1) + " + pageableFoo1FooVMAddr
) 
 158         print "pageableFoo1FooFixupAddr: " + pageableFoo1FooFixupAddr
 
 160     # Then the following fixup should be to KernelClass::kernelClassUsed0() 
 161     pageableFoo1FooNextFixupAddr 
= offsetVMAddr(pageableFoo1FooFixupAddr
, 8) 
 163         print "pageableFoo1FooNextFixupAddr: " + pageableFoo1FooNextFixupAddr
 
 164     assert kernel_cache
.dictionary()["dylibs"][0]["fixups"][pageableFoo1FooNextFixupAddr
] == "kc(0) + " + kernelClassUsed0VMOffset
 
 166     # Then we should have foo1Used0() 
 167     pageableFoo1FooNextFixupAddr 
= offsetVMAddr(pageableFoo1FooFixupAddr
, 16) 
 169         print "pageableFoo1FooNextFixupAddr: " + pageableFoo1FooNextFixupAddr
 
 170     assert kernel_cache
.dictionary()["dylibs"][0]["fixups"][pageableFoo1FooNextFixupAddr
] == "kc(1) + " + pageableFoo1FooUsed0VMAddr
 
 172     # And then foo1Used1() 
 173     pageableFoo1FooNextFixupAddr 
= offsetVMAddr(pageableFoo1FooFixupAddr
, 24) 
 175         print "pageableFoo1FooNextFixupAddr: " + pageableFoo1FooNextFixupAddr
 
 176     assert kernel_cache
.dictionary()["dylibs"][0]["fixups"][pageableFoo1FooNextFixupAddr
] == "kc(1) + " + pageableFoo1FooUsed1VMAddr
 
 179     # The vtable we have is [ ..., foo(), kernelClass_RESERVED0(), foo1Used0(), foo1_RESERVED1() ] 
 180     # and we want           [ ..., foo(), kernelClassUsed0(),      foo1Used0(), foo1Used1() ] 
 182     # In vtable for Foo2, we match the entry for Foo2::foo() by looking for its value on the RHS of the fixup 
 183     pageableFoo2FooFixupAddr 
= findPagableFixupVMAddr(kernel_cache
, 1, "kc(1) + " + pageableFoo2FooVMAddr
) 
 185         print "pageableFoo2FooFixupAddr: " + pageableFoo2FooFixupAddr
 
 187     # Then the following fixup should be to KernelClass::kernelClassUsed0() 
 188     pageableFoo2FooNextFixupAddr 
= offsetVMAddr(pageableFoo2FooFixupAddr
, 8) 
 190         print "pageableFoo2FooNextFixupAddr: " + pageableFoo2FooNextFixupAddr
 
 191     assert kernel_cache
.dictionary()["dylibs"][1]["fixups"][pageableFoo2FooNextFixupAddr
] == "kc(0) + " + kernelClassUsed0VMOffset
 
 193     # Then we should have foo1Used0(), but Foo2 overrides that, so it should be the Foo2 implementation, not the Foo1 implementation 
 194     pageableFoo2FooNextFixupAddr 
= offsetVMAddr(pageableFoo2FooFixupAddr
, 16) 
 196         print "pageableFoo2FooNextFixupAddr: " + pageableFoo2FooNextFixupAddr
 
 197     assert kernel_cache
.dictionary()["dylibs"][1]["fixups"][pageableFoo2FooNextFixupAddr
] == "kc(1) + " + pageableFoo2FooUsed0VMAddr
 
 199     # And then foo1Used1() 
 200     pageableFoo2FooNextFixupAddr 
= offsetVMAddr(pageableFoo2FooFixupAddr
, 24) 
 202         print "pageableFoo2FooNextFixupAddr: " + pageableFoo2FooNextFixupAddr
 
 203     assert kernel_cache
.dictionary()["dylibs"][1]["fixups"][pageableFoo2FooNextFixupAddr
] == "kc(1) + " + pageableFoo1FooUsed1VMAddr
 
 206     # ----------------------------------------------------------- 
 207     # Now build an aux cache using the baseline kernel collection 
 208     kernel_cache
.buildAuxKernelCollection("x86_64", "/auxkc-pageablekc-vtable-patching-namespaces-locals/aux.kc", "/auxkc-pageablekc-vtable-patching-namespaces-locals/main.kc", "/auxkc-pageablekc-vtable-patching-namespaces-locals/pageable.kc", "/auxkc-pageablekc-vtable-patching-namespaces-locals/extensions", ["com.apple.bar1", "com.apple.bar2"], []) 
 209     kernel_cache
.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/aux.kc", ["-layout", "-arch", "x86_64"]) 
 211     assert len(kernel_cache
.dictionary()["dylibs"]) == 2 
 212     assert kernel_cache
.dictionary()["dylibs"][0]["name"] == "com.apple.bar1" 
 213     assert kernel_cache
.dictionary()["dylibs"][1]["name"] == "com.apple.bar2" 
 216     # Get the addresses for the symbols we are looking at.  This will make it easier to work out the fixup slots 
 217     kernel_cache
.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/aux.kc", ["-symbols", "-arch", "x86_64"]) 
 219     # From bar1, find the vtable and its override of foo() 
 221     auxBar1FooVMAddr 
= findLocalSymbolVMAddr(kernel_cache
, 0, "__ZN1X4Bar13fooEv") 
 223         print "auxBar1FooVMAddr: " + auxBar1FooVMAddr
 
 225     # From bar2, find the vtable and its override of foo() 
 227     auxBar2FooVMAddr 
= findLocalSymbolVMAddr(kernel_cache
, 1, "__ZN4Bar23fooEv") 
 229         print "auxBar2FooVMAddr: " + auxBar2FooVMAddr
 
 233     kernel_cache
.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/aux.kc", ["-fixups", "-arch", "x86_64"]) 
 236     # The vtable we have is [ ..., foo(), kernelClass_RESERVED0(), foo1Used0(), foo1Used1() ] 
 237     # and we want           [ ..., foo(), kernelClassUsed0(),      foo1Used0(), foo1Used1() ] 
 239     # In vtable for Bar1, we match the entry for Bar1::foo() by looking for its value on the RHS of the fixup 
 240     auxBar1FooFixupAddr 
= findAuxFixupVMAddr(kernel_cache
, 0, "kc(3) + " + auxBar1FooVMAddr
) 
 242         print "auxBar1FooFixupAddr: " + auxBar1FooFixupAddr
 
 244     # Then the following fixup should be to KernelClass::kernelClassUsed0() 
 245     auxBar1FooNextFixupAddr 
= offsetVMAddr(auxBar1FooFixupAddr
, 8) 
 247         print "auxBar1FooNextFixupAddr: " + auxBar1FooNextFixupAddr
 
 248     assert kernel_cache
.dictionary()["dylibs"][0]["fixups"][auxBar1FooNextFixupAddr
] == "kc(0) + " + kernelClassUsed0VMOffset
 
 250     # Then we should have foo1Used0() from Foo2 as it overrides it from Foo1 
 251     auxBar1FooNextFixupAddr 
= offsetVMAddr(auxBar1FooFixupAddr
, 16) 
 253         print "auxBar1FooNextFixupAddr: " + auxBar1FooNextFixupAddr
 
 254     assert kernel_cache
.dictionary()["dylibs"][0]["fixups"][auxBar1FooNextFixupAddr
] == "kc(1) + " + pageableFoo2FooUsed0VMAddr
 
 256     # And then foo1Used1() 
 257     auxBar1FooNextFixupAddr 
= offsetVMAddr(auxBar1FooFixupAddr
, 24) 
 259         print "auxBar1FooNextFixupAddr: " + auxBar1FooNextFixupAddr
 
 260     assert kernel_cache
.dictionary()["dylibs"][0]["fixups"][auxBar1FooNextFixupAddr
] == "kc(1) + " + pageableFoo1FooUsed1VMAddr
 
 263     # The vtable we have is [ ..., foo(), kernelClass_RESERVED0(), foo1Used0(), foo1_RESERVED1() ] 
 264     # and we want           [ ..., foo(), kernelClassUsed0(),      foo1Used0(), foo1Used1() ] 
 266     # In vtable for Foo2, we match the entry for Foo2::foo() by looking for its value on the RHS of the fixup 
 267     auxBar2FooFixupAddr 
= findAuxFixupVMAddr(kernel_cache
, 1, "kc(3) + " + auxBar2FooVMAddr
) 
 269         print "auxBar2FooFixupAddr: " + auxBar2FooFixupAddr
 
 271     # Then the following fixup should be to KernelClass::kernelClassUsed0() 
 272     auxBar2FooNextFixupAddr 
= offsetVMAddr(auxBar2FooFixupAddr
, 8) 
 274         print "auxBar2FooNextFixupAddr: " + auxBar2FooNextFixupAddr
 
 275     assert kernel_cache
.dictionary()["dylibs"][1]["fixups"][auxBar2FooNextFixupAddr
] == "kc(0) + " + kernelClassUsed0VMOffset
 
 277     # Then we should have foo1Used0() from Foo2 as it overrides it from Foo1 
 278     auxBar2FooNextFixupAddr 
= offsetVMAddr(auxBar2FooFixupAddr
, 16) 
 280         print "auxBar2FooNextFixupAddr: " + auxBar2FooNextFixupAddr
 
 281     assert kernel_cache
.dictionary()["dylibs"][1]["fixups"][auxBar2FooNextFixupAddr
] == "kc(1) + " + pageableFoo2FooUsed0VMAddr
 
 283     # And then foo1Used1() 
 284     auxBar2FooNextFixupAddr 
= offsetVMAddr(auxBar2FooFixupAddr
, 24) 
 286         print "auxBar2FooNextFixupAddr: " + auxBar2FooNextFixupAddr
 
 287     assert kernel_cache
.dictionary()["dylibs"][1]["fixups"][auxBar2FooNextFixupAddr
] == "kc(1) + " + pageableFoo1FooUsed1VMAddr
 
 289 # [~]> xcrun -sdk macosx.internal cc -arch x86_64 -Wl,-static -mkernel -nostdlib -Wl,-e,__start -Wl,-pie main.cpp kernel.cpp -Wl,-pagezero_size,0x0 -o main.kernel -Wl,-image_base,0x10000 -Wl,-segaddr,__HIB,0x4000 -Wl,-add_split_seg_info -Wl,-install_name,/usr/lib/swift/split.seg.v2.hack -iwithsysroot /System/Library/Frameworks/Kernel.framework/Headers -Wl,-sectcreate,__LINKINFO,__symbolsets,SymbolSets.plist -Wl,-segprot,__LINKINFO,r--,r-- -std=c++11 -DKERNEL_USED=1 -Wl,-exported_symbol,__ZN1X11KernelClass10gMetaClassE -Wl,-exported_symbol,__ZN8OSObject10gMetaClassE -Wl,-exported_symbol,__ZNK11OSMetaClass19instanceConstructedEv 
 290 # [~]> xcrun -sdk macosx.internal cc -arch x86_64 -Wl,-kext -mkernel -nostdlib -Wl,-add_split_seg_info -Wl,-no_data_const foo1.cpp -o extensions/foo1.kext/foo1 -iwithsysroot /System/Library/Frameworks/Kernel.framework/Headers -std=c++11 -DFOO1_USED0=1  -DFOO1_USED1=1 -Wl,-exported_symbol,__ZN1X4Foo110gMetaClassE -Wl,-exported_symbol,__ZN1X4Foo1C2EPK11OSMetaClass -Wl,-exported_symbol,__ZTVN1X4Foo1E -Wl,-exported_symbol,__ZN1X4Foo1D2Ev 
 291 # [~]> xcrun -sdk macosx.internal cc -arch x86_64 -Wl,-kext -mkernel -nostdlib -Wl,-add_split_seg_info -Wl,-no_data_const foo2.cpp -o extensions/foo2.kext/foo2 -iwithsysroot /System/Library/Frameworks/Kernel.framework/Headers -std=c++11 -DFOO1_USED0=1 -Wl,-exported_symbol,__ZN1X4Foo210gMetaClassE -Wl,-exported_symbol,__ZN1X4Foo2C2EPK11OSMetaClass -Wl,-exported_symbol,__ZTVN1X4Foo2E -Wl,-exported_symbol,__ZN1X4Foo2D2Ev 
 292 # [~]> xcrun -sdk macosx.internal cc -arch x86_64 -Wl,-kext -mkernel -nostdlib -Wl,-add_split_seg_info -Wl,-data_const bar1.cpp -o extensions/bar1.kext/bar1 -iwithsysroot /System/Library/Frameworks/Kernel.framework/Headers -std=c++11 -DFOO1_USED0=1 -Wl,-exported_symbol,__ZN1X4Bar110gMetaClassE -Wl,-exported_symbol,__ZN1X4Bar1C2EPK11OSMetaClass -Wl,-exported_symbol,__ZTVN1X4Bar1E -Wl,-exported_symbol,__ZN1X4Bar1D2Ev 
 293 # [~]> xcrun -sdk macosx.internal cc -arch x86_64 -Wl,-kext -mkernel -nostdlib -Wl,-add_split_seg_info -Wl,-data_const bar2.cpp -o extensions/bar2.kext/bar2 -iwithsysroot /System/Library/Frameworks/Kernel.framework/Headers -std=c++11 -DFOO1_USED0=1