일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- pwn
- 리커버릿
- GEF
- Windows 부팅 오류
- python
- Seccomp bypass
- std::cerr
- 공유 라이브러리는 왜 항상 같은 순서로 맵핑 될까?
- Python3
- 실시간로깅
- 지훈현서
- GDB
- python3.11 pip
- Python.h: No such file or directory
- 임베디드 시스템 해킹
- c++
- Recoverit
- pwntools
- z3 signed 이슈
- vmware 반응 속도
- python3.11 설치
- VSCode C++ 표준 버전 수정
- docker
- DYNAMIC Section
- pip 에러 해결
- 개발
- tool
- OpenAI 개발
- wsl2 복구
- vhdx 파일 복구
- Today
- Total
OZ1NG의 뽀나블(Pwnable)
[C++] new operator 정적 할당(된 곳에 변수 할당) 본문
[*] tcmalloc을 분석하다가 아래와 같은 코드를 봤는데 뭔지 잘모르겠어서 삽질해보게 되었다.
new (&pageheap_.memory) PageHeap;
먼저 두괄식으로 결과부터 말하자면 보통 C++에서 동적 할당할 때 사용하는 new operator는 정적할당도 가능하다는 것이다. (정확히는 정적할당된 공간에 클래스를 저장한다)
[*] 사용법
new (void * address) Class;
위와 같은 형태로 구성된다.
결과 : address에 Class가 할당된다.
정적 변수에 클래스를 할당 할 수 있다.
[*] 테스트 코드
// cpp new test
#include <iostream>
using namespace std;
class PageHeap{
public:
int a = 1;
int b = 2;
PageHeap(){
cout << "PageHeap!" << endl;
a = 3;
}
};
union PageHeapStorage {
char memory[sizeof(PageHeap)];
uintptr_t aaaa;
};
static PageHeapStorage pageheap_;
int main(){
// new로 먼저 공간을 할당 한 뒤, PageHeap 생성자가 실행됨 // pageheap_의 주소를 리턴
new (&pageheap_.memory) PageHeap;
// cout << "a" << &pageheap_.memory.a << endl; // 자료형이 바뀐게 아니라 진짜 저장만 하는 용도이기 때문에 접근 불가
return 0;
}
oz1ng@LAPTOP-6F0C4A2N:/mnt/c/Users/ghdxo/Desktop/oz1ng_Lab/tcmalloc/test$ ./new_test
PageHeap!
생성자가 실행되는 것을 확인 할 수 있다.
[*] Assembly 코드
pwndbg> disassemble
Dump of assembler code for function main:
...
0x00000000004011c7 <+17>: lea rbx,[rip+0x2fd2] # 0x4041a0 <pageheap_>
0x00000000004011ce <+24>: mov rsi,rbx
0x00000000004011d1 <+27>: mov edi,0x8
0x00000000004011d6 <+32>: call 0x40127b <operator new(unsigned long, void*)> // [A]
0x00000000004011db <+37>: mov r12,rax
0x00000000004011de <+40>: mov rdi,r12
0x00000000004011e1 <+43>: call 0x4012a4 <PageHeap::PageHeap()> // [B]
0x00000000004011e6 <+48>: mov eax,0x0
0x00000000004011eb <+53>: jmp 0x40120a <main+84>
...
End of assembler dump.
- [A] :
1. operator new(unsigned long, void*) 함수를 사용하여 메모리 할당을 시도한다.
2. 첫 번째 인자인 rdi에는 sizeof(PageHeap) 값이 들어가고, 두 번째 인자인 rsi에 ()안의 명시해준 address인 pageheap_의 주소 값이 들어간다.
- [B] : HeapPage 클래스의 생성자를 호출한다.
- [B]까지의 실행 결과
pwndbg> x/2gx 0x4041a0
0x4041a0 <pageheap_>: 0x0000000200000003 0x0000000000000000
[*] 결과
멤버 변수 a와 b에 해당하는 부분이 각각 2와 3으로 바뀐것으로 pageheap_에 PageHeap 클래스가 정적 변수에 할당되었다는 것을 확인 할 수 있다.
[+] 추가 : new operator를 동적할당 했을때의 어셈코드 비교
// c
int main(){
PageHeap * a = new PageHeap;
return 0;
}
// asm
pwndbg> disassemble
Dump of assembler code for function main:
...
0x0000000000401205 <+15>: mov edi,0x8
0x000000000040120a <+20>: call 0x4010c0 <operator new(unsigned long)@plt> // [A]
0x000000000040120f <+25>: mov rbx,rax
0x0000000000401212 <+28>: mov rdi,rbx
0x0000000000401215 <+31>: call 0x4012b4 <PageHeap::PageHeap()>
0x000000000040121a <+36>: mov QWORD PTR [rbp-0x18],rbx
0x000000000040121e <+40>: mov eax,0x0
0x0000000000401223 <+45>: jmp 0x401244 <main+78>
...
End of assembler dump.
- [A]
1. : operator new(unsigned long)@plt 함수를 호출한다.
즉, new 함수는 오버로드 함수로 인자에 따라 호출되는 new 함수가 다르다는 것을 알 수 있다.
(때문에 new 연산자를 사용했을 때, rsi에 값이 있다고 정적할당과 같이 쓸 수는 없다...)
[*] 종합
1. new operator는 동적할당 뿐만 아니라 정적할당 또한 가능하다.
2. 동적할당할 때와 정적할당 할 때의 new operator는 서로 다른 오버로드된 함수를 사용하여 구분한다.
3. 정적할당할 때의 new operator는 첫 번째 인자로 size 값, 두 번째 인자로 정적 할당할 주소를 사용한다.
4. 동적할당할 때의 new operator는 첫 번째 인자로 size 값만을 받는다.
'Tips' 카테고리의 다른 글
[C++] volatile Keyword (0) | 2022.07.25 |
---|---|
[C++] 클래스 생성자의 첫 번째 인자 (0) | 2022.07.19 |
[C/C++] 구조체 bitfield 멤버 변수 선언 ( ':' ) (0) | 2022.07.19 |
[C/C++] Capstone 라이브러리 (disassembly 라이브러리) (0) | 2022.07.18 |
[Python3] 인코딩 범위 무시하고 순수 바이트 값으로 디코딩 하기 (bytes.decode(errors="surrogateescape")) (0) | 2022.07.14 |