필자 구매 품목 (추천!)

  • 라즈베리파이 5 16GB
  • PCIE to M.2 HAT (2340 규격)
  • M.2 NVMe 2340 128GB
  • M.2 NVMe 외장 케이스
  • Micro HDMI to HDMI 변환기
  • 5V 5A 어댑터 (필수)

1. PC에 M.2 USB장착

2. Raspberry Pi Imager 다운로드 및 실행. 라즈베리파이 OS 선택 후 설치 (전력 문제로 우분투 설치는 추천하지 않음. 마우스가 먹통이 되거나, 와이파이 연결이 안됨)

3. 라즈베리파이에 M.2 장착 후 부팅

4. $sudo vi /boot/firmware/config.txt

dtparam밑에 dtparam=pciex1_gen3 추가

 

 

Kyber는 키 캡슐화 메커니즘으로, 쉽게 설명하면 공유 키(AES)를 유도할때 사용한다고 보면 된다.

Kyber의 보안 강도는 아래와 같다.

Kyber-512 = AES-128

Kyber-768 = AES-192

Kyber-1024 = AES-256

매개변수 세트 공개키 사이즈 개인키 사이즈 암호문 사이즈 공유키 사이즈
Kyber512 800 바이트 1632 바이트 768 바이트 32 바이트
Kyber768 1184 바이트 2400 바이트 1088 바이트 32 바이트
Kyber1024 1568 바이트 3168 바이트 1568 바이트 32 바이트

 

테스트 코드 : https://github.com/pq-crystals/kyber 빌드 후, test_vectors를 실행

*공식에서는 Kyber768 사용을 권장하지만, 귀찮아서 그냥 Kyber512로 진행하였음

1. Bob이 공개 키와 비밀 키를 생성

Public Key: c29ac66c84bee3f129508c2b8c790c99a5ca41e5707e9b8c75c04d7ea8a481980a358b066a4a7e28d15d10374f75c33da6029cd490746fb55f5feab2ce823dec1830c0c18ef89ba3cc3bce4d252a07a40d401a4c8d273618b595db21ca4a959eb4d133556801b2b78254b2b5955c0400962dbb5a487aaa24a430b614e2af9338afd4b0339bd830a9cb761db1a83220352dd523b8a583022ca13e246506548c57ba3850ac5c50d864e2d48b89694277cc7a8174ad7b1ba2ee621d57d29b23c22df831872051145d2535dbb025e29c6da38cb475958e2a8808a431bed5b486821a1513a729cd979b6c8b382503cf53337616e1059ddc59977219d2f17b32acabbe86c468c1267b2b862ac565a7e232266c83fc700cda19b616377389428e62614cd6ac9f08fb12d21827feb324b14bc16cc0c20904b3973b9dfe60af577776449ac34eb00989e5a876143bc9b930a3c2a5bb861208f225dd97625bb36b2d8810d0452e458968b90c6a6d97c2dfca7341d53c741a60e2b91385c86bb3b1be5f10708c546ae6318209ba268dd2b4e3e4722761491ae215600248e7541e6080b865f44a169c02a5b374f1fa5502333753979c9da75452c4814a8b8fd682b8e0370699296bc2f42d38e5a2de92c5f5f61f24b65e1b9b75249b8759708706640000b490937683e1ccbbf39a0baecb1edd62826721524bcc4d3bf06f8e5ab368aa426eb42c701839e8bbcc69dbccd2757f84c60a409b6629d98dc92947367c52f0698c3c41c01110bafbeb0621cc175170375f8250c0f62406e32e10725b47e3c165845a7ada8fb2c55555f5cc8602246fe06f875a6eb5c9459dd19292428492a76738b8057e84c8e11436c4eb788e494e3952657ed331a2e4a47d75492365c473f484200502868c733bb9b2b3e44af2c98adfb91a4e1a144eec5a32d24f13c78775f206d7a94dee12007f778e484a1430666bfeda6dbb31b757d72b5c79a469522fe6599abb45b52cc6403c4970f65684bb770ca78893ba439057013655309cd84c524c9ca558e3612041b7b2026e2187598afb46f1d4ca85096dbc9bcc1c25779dfb607052e11649bb7f5f7268f979c4d8140afe6ce53830f38602290d751427f07b27
Secret Key: 7cf108c75a4d3592053d0ca79ce527ec1734f7023656e26253e2bfc68960dea73d28d7a9821597b48b4504837e27132c8ebc48505303aeb568f9d1928f7244cf98b4a88843c5db69845abfc4e40683dca3bde694445c63cc512bd2e4608e91a5697738bbca3b09a98da49757ad65c085125d11d01178d15acb251f417cbeff2a2ac1b05dc70839ffb297be205152e98371745de76243d3a302dfda7f16f5a8f0d2b73021a7f5c0490ff6b5a4125843889364288bede430835cce5bf8b86377132aea3ced911311a43b87e10ae471b49f1a31b636ce5d7c415d7c17539575724c3166ab23ca183f9962a0b17190f3dc204dc2551eec234b7c4e298a4e60f15d4e40bcaf1ba0eaa806e214bda0a0b0e0f51b34745e148290e222a4496c946766029cd82964429fd85a30ee3c0c6dea4e6bc840237c38d8e9b6a893702444bfeef783a104a8b46b8309a914cbaaa8cec9c08bb54a3cfc1a22c5a9d1b87685a30417d846d5e22242e8c0c8316cb7f15832b70b4bbc453bb67485e34c87d9a2d4b294d257a98d864afab445aea6bf4830404d170ca7484cc799b73ae3ce375c3a13d1318bd29158620328c8bc22d812d269c8ec133ce4f977bd95300054b5ef246bb086a6d3340575464183e10db1a126f81a43d2f800e962568de3411515b90dc1256446cf8fc33149e66a8657c221335eb57a8ca6262b06981a032823222c9da22835271033212b4e9d516132a428709b5882ab8764771832968dc73c4cd241adb145b5e654b38bab03e3524f113525dd0a63e8f195fceb26b8b03063c4863459cc10c5884cac016eebb7afa2519b27293b845e7e893e70bb21d0e004f1d05015dc71fcf6b150c750aa98c96f89c8da199eefc1712c409bc833a84d404ad72c873bf910c9190645b94dd2a31347596029d22abd071f5387588a9917fee4b33d1bbcfa1858390662b656c09ff824ed177abf44a118b7c78bba96b9f9b5a3a54e597829be686868e5463f99be58da0be7886501730e01e26aad0535896616d98125c38b3eb778114176b1bd498ebd92b5bd0a98a0a39f77b599c3e63e66fb62167b06c29ac66c84bee3f129508c2b8c790c99a5ca41e5707e9b8c75c04d7ea8a481980a358b066a4a7e28d15d10374f75c33da6029cd490746fb55f5feab2ce823dec1830c0c18ef89ba3cc3bce4d252a07a40d401a4c8d273618b595db21ca4a959eb4d133556801b2b78254b2b5955c0400962dbb5a487aaa24a430b614e2af9338afd4b0339bd830a9cb761db1a83220352dd523b8a583022ca13e246506548c57ba3850ac5c50d864e2d48b89694277cc7a8174ad7b1ba2ee621d57d29b23c22df831872051145d2535dbb025e29c6da38cb475958e2a8808a431bed5b486821a1513a729cd979b6c8b382503cf53337616e1059ddc59977219d2f17b32acabbe86c468c1267b2b862ac565a7e232266c83fc700cda19b616377389428e62614cd6ac9f08fb12d21827feb324b14bc16cc0c20904b3973b9dfe60af577776449ac34eb00989e5a876143bc9b930a3c2a5bb861208f225dd97625bb36b2d8810d0452e458968b90c6a6d97c2dfca7341d53c741a60e2b91385c86bb3b1be5f10708c546ae6318209ba268dd2b4e3e4722761491ae215600248e7541e6080b865f44a169c02a5b374f1fa5502333753979c9da75452c4814a8b8fd682b8e0370699296bc2f42d38e5a2de92c5f5f61f24b65e1b9b75249b8759708706640000b490937683e1ccbbf39a0baecb1edd62826721524bcc4d3bf06f8e5ab368aa426eb42c701839e8bbcc69dbccd2757f84c60a409b6629d98dc92947367c52f0698c3c41c01110bafbeb0621cc175170375f8250c0f62406e32e10725b47e3c165845a7ada8fb2c55555f5cc8602246fe06f875a6eb5c9459dd19292428492a76738b8057e84c8e11436c4eb788e494e3952657ed331a2e4a47d75492365c473f484200502868c733bb9b2b3e44af2c98adfb91a4e1a144eec5a32d24f13c78775f206d7a94dee12007f778e484a1430666bfeda6dbb31b757d72b5c79a469522fe6599abb45b52cc6403c4970f65684bb770ca78893ba439057013655309cd84c524c9ca558e3612041b7b2026e2187598afb46f1d4ca85096dbc9bcc1c25779dfb607052e11649bb7f5f7268f979c4d8140afe6ce53830f38602290d751427f07b27cda93dec4c4dc4d8484457fd882399c4b918c49fa8389a1dfa8c9f92f39b00cf3cb1eea988004b93103cfb0aeefd2a686e01fa4a58e8a3639ca8a1e3f9ae57e2

2. Alice는 Bob의 공개 키를 사용하여 공유 키를 유도하고, 이를 캡슐화 함

Ciphertext: 5a645120b878936d202efc4851f38e6bb6573c3b14b0b9bb44bf372d8b1aa8034a9f1a1584076f0a38e89a9d49a50b792ace7584981be8e239272deef914418fefe2dad97dc0ec20cfe8a9599b9bbe3ecce91f97e10cd9ef2c4950e3ea3c46fe481eb0d24878c4624ad344f0dc9863e7d170937a8cecc6f7d00f9565529d572959cc49d0f7042ff43b7d1d71efd22f2654e14e78c31f34a26ae53b067ae0380a65a732459503da5e9406d50a70e3d5ebdbf3c9c01cad1cc001ebe69e6cff20e64ce5c802b691587e404cf6efa2799a2ffd353492a75f0e2ea52a974e0545a086a3bd14b69045238140a7200b10c3276cc6b2a67c173f7c1ad64545adb8ebdf7835e9aa1f54f6891369988f3625c45f2fec8d9a07b911d32ba69d9ff5d74f10a6808b25a3c81709945bf213c3450d74481f065042186b0d36fb55271162dfaf41e516a408f83ccabe8a0ba7effa16f88f6d7dbdb64e608c8f18d686c7e5d548d737116fa562dc76e7994a86374a9c85b8b17c4f025fa23a4de1a997a87e5a65f5c5386772491fd8d10731f5f5aa60366ffe3fd209cb7b7a8615320ad0728f41e812bd88d2d6104753917e89e1ca0f10177cf5dab040e466908b27446215709b0912972c428c4d9aad9432d9a159069c96154001cb0be4de597e9871b04bddaa4539f838bc12ab0a3ea7e8c8481bcdfcc1834369fcf061f7c599efdc4f6c434102991446aea12881e163fd4ee6c458b82e42759f8b11b0612c12d5a777acf4c7cdd26fb7da0b9098dc4af94704daa529945ab169cdb22d3966fcd26950e2418cac9bc7dc32c4a604f368f0f8a9c7ddce8b5e476b26b33116d607df1b49c205ada0d2ea5a5a64eecb22549ddf18a0daed2e5d44cb6174b9781236eee11f95ab0c45836bcafc73af3bec11440bc1c605669eb019cfac0097943cf29bbffce0f823293da623e5fa6d2a7ee0c7b4507596a62ef46bbe4e1b63cc96ba9878a7b39f84b59dd336f1659a24cbb33015d515e9e80e3e7902b1d583f8ee97153cd8ba1fadeb9ee7e2f2c23dfee85a50d5c3554b79922a4537d6dc4f09418dfdd744596cbf68
Shared Key: 221d7d86011659313c83ce3fd0ab26797ef217e11d1f0bc76e7952fbe52a0a58

3. Bob은 Alice가 보낸 캡슐화된 키를 자신의 비밀 키로 복호화하여 Alice와 동일한 공유키를 얻음

Shared Key: 221d7d86011659313c83ce3fd0ab26797ef217e11d1f0bc76e7952fbe52a0a58

 

Kyber 공식 홈페이지에서는 하이브리드를 권장한다. 예) Kyber+ECDH
키 교환에 대해서는 아래를 참조
https://www.ietf.org/archive/id/draft-ietf-tls-hybrid-design-12.html

 

만약 크롬을 사용중이라면, 아래에 접속하여 TLS 1.3 kyber 사용을 활성화 할 수 있다.

 

 

1. 환경 설정 (wsl 기준)

$ git clone https://github.com/emscripten-core/emsdk.git
$ cd emsdk
$ ./emsdk install latest
$ ./emsdk activate latest
$ source ./emsdk_env.sh
$ emcc --version

2. hello.c 작성

#include <stdio.h>

int main() {
    printf("Hello World\n");
    return 0;
}

3. 컴파일

emcc hello.c -o hello.html

4. 서버 구동

npx http-server ~ -o -p 9999


참고

https://emscripten.org/docs/getting_started/downloads.html#sdk-download-and-install

https://emscripten.org/docs/tools_reference/emcc.html#emccdoc

https://developer.mozilla.org/ko/docs/WebAssembly/C_to_Wasm


알아낸 것 1. 샌드 박스 내부는 리눅스 스타일로 구성되어 있음. 아래는 직접 돌려본 예시

/tmp
/home
/home/web_user
/dev
/dev/null
/dev/tty
/dev/tty1
/dev/random
/dev/urandom
/dev/shm
/dev/shm/tmp
/dev/stdin
/dev/stdout
/dev/stderr
/proc
/proc/self
/proc/self/fd
/proc/self/fd/0
/proc/self/fd/1
/proc/self/fd/2
/proc/self/fd/3
/proc/self/fd/4
/proc/self/fd/5
/proc/self/fd/6

알아낸 것  2. C코드로 디컴파일 가능

LLVM 기반이기 때문에 OLLVM 개발 가능

https://github.com/HakonHarnes/emcc-obf

알아낸 것  3. int main()의 주소는 0x1

이것은 전형적인 메모리 레이아웃은 아님

예제 참조 : https://github.com/codetronik/KeyStoreExample

아래 코드를 실행하면, certificateChain에 인증서 체인이 저장된다.

val kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore")

kpg.initialize(
		KeyGenParameterSpec.Builder(SIGN_KEY_ALIAS, KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY)
			.setAttestationChallenge(challenge)
			.setIsStrongBoxBacked(isStrongBoxSupported())
			.build())

kpg.generateKeyPair()

val certificateChain = keyStore.getCertificateChain(SIGN_KEY_ALIAS)

인증서는 총 4개(리프, 중간-1, 중간-2, 루트 순)로 구성되어 있다. (구형 기기는 다름)

루트 인증서는 고정이며, 중간 인증서 2개는 발급자가 기기마다.. ?? (같은 모델에서 확인 필요)

루트 인증서의 공개키는 https://developer.android.com/privacy-and-security/security-key-attestation?hl=ko#root_certificate에서 제공하는 것과 일치한다. 이 키로 루트 인증서 및 중간-2 인증서를 검증한다.

만약, vendor로부터 직접 전달받은 출시 전 테스트폰이라면, 구글 루트 인증서가 아닌, 벤더 루트 인증서일 확률이 높다.

중간-2 인증서로 중간-1 인증서를 검증한다.

중간-1 인증서로 리프 인증서를 검증한다.

리프 인증서에는 확장 OID 1.3.6.1.4.1.11129.2.1.17 가 존재하며, 기기증명 콘텐츠가 포함되어 있다.

각 항목에 대한 설명은 아래 링크에 참고

https://source.android.com/docs/security/features/keystore/attestation?hl=ko

https://developer.android.com/privacy-and-security/security-key-attestation?hl=ko

아래는 나의 갤럭시 S20 노트에서 확인한 기기증명 콘텐츠이다.

이름 비고
attestationVersion  3 키마스터2 = 1, 키마스터3 = 2, 키마스터4 = 3
attestationSecurityLevel 2 SW = 0, TEE = 1, StrongBox = 2
keymasterVersion 4  
keymasterSecurityLevel 4 SW = 0, TEE = 1, StrongBox = 2
attestationChallenge 챌린지 키쌍 생성 시 설정한 챌린지
uniqueId 없음  
softwareEnforced    
- creationDateTime 3810012308008 콘텐츠 생성 시간
- attestationApplicationId HEX값 앱 패키지 이름 및 앱을 서명한 인증서의 지문(SHA-256) -> 인증서를 sha256하면 지문을 얻을 수 있음
teeEnforced    
- purpose 2, 3 SIGN = 2, VERIFY = 3
- algorithm 3 RSA = 1, EC = 3
- keySize 256  
- ecCurve 1 P_256 = 1, P_384 = 2, P_512 = 3
- noAuthRequired true  
- origin 0 키가 생성된 위치 (생성 = 0, 유도 = 1, 임포트 = 2, 모름 = 3)
- rootOfTrust    
-- verifiedBootKey HEX값  
-- deviceLocked true 부트로더 잠김 여부
-- verifiedBootState 0 검증됨 = 0, 자체 서명 = 1, 검증 안됨 = 2, 실패 = 3
-- verifiedBootHash HEX값  
- osVersion 130000 Android 13
- osPatchLevel 202410 키마스터 보안 패치 날짜
- vendorPatchLevel 20241001 기기의 증명키 생성 날짜
- bootPatchLevel 20241001 기기의 증명키 생성 날짜

 

VS 2022 17.11.5버전 기준

1. 최신 NDK 다운로드

2. 원본 C:\Program Files (x86)\Android\AndroidNDK\android-ndk-r23c 백업 및 해당 경로에 최신 NDK 덮어 씌우기

3. 텍스트 편집기를 관리자 권한으로 실행 후, 아래 경로를 로드

C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Application Type\Android\3.0\Android.Common.props

isystem 문자열 검색 후, 아래 파란 라인을 삭제

VS 프로젝트 -> 속성페이지 -> C/C++ -> 명령줄 -> 모든 옵션에서 -isystem이 사라진 것을 확인

(최신 NDK와 호환되지 않는 경로 설정을 삭제)

4. 텍스트 편집기를 관리자 권한으로 실행 후, 아래 두 개의 경로를 로드

C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Application Type\Android\3.0\Platforms\ARM\PlatformToolsets\Clang_5_0\toolset.props

C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Application Type\Android\3.0\Platforms\ARM64\PlatformToolsets\Clang_5_0\toolset.props

lib64 문자열 검색 후, 아래처럼 lib\clang\18로 변경 (경로마다 각각 변경)

6. 빌드

1. windows에서 CRLF를 사용한다면, 맥에서도 CRLF로 변경해야함.

Xcode -> Settings -> Text Editing -> Editing -> Default Line Endings을 CRLF로 변경

2. 맥에서는 UTF8(BOM)을 지원하지 않으므로, windows에서 UTF8(BOM)으로 작업하고 있었다면 UTF8로 변경해줘야 함

이 두가지를 맞추지 않으면, git 작업 시 애로사항이 꽃 핀다.

하나 이상의 헤더를 Public으로 설정하지 않아서 발생하는 에러이다.

또한, 프로젝트명과 파일명이 동일하여야 한다.

const 선언할 경우 해당 함수의 this는 const가 된다.

즉, 수정 불가능한 상태가 된다. 따라서, this의 모든 멤버 변수에 접근할 수 없다.

또한, 해당 함수에서는 비 const 함수를 호출할 수 없다. 왜냐면 비 const함수에서는 멤버 변수가 수정될 수 있기 때문이다.

class AA {
public:
    AA() = default;
    ~AA() = default;

    void printData(int value) const
    {
        std::cout << this->data;
        this->data = value; // 에러 
        changeData(); // 에러
    }

    void changeData(int value) 
    {
        this->data = value;
    }

private:
    int data = 0;
};
int main()
{
    std::cout << "Hello World!\n";
}

 

 

'Language > C++' 카테고리의 다른 글

[folly] 구축 및 로그 예제  (0) 2025.10.31
[poco] 로그 예제  (0) 2025.07.22
[C++20] std::span  (0) 2025.05.25

환경: c++20, 최적화 끔(-O0), 릴리즈 빌드

테스트 1

class A
{
public:
    void foo()
    {
        printf("hello %d\n", var);
    }
    void set(int a)
    {
        this->var = a;  
    }
private:
    int var = 100;
};

int main()
{
    A a;
    a.foo();
    A b;
    b = a;
    b.foo();
 }

아래는 IDA 디컴파일

int __fastcall main(int argc, const char **argv, const char **envp)
{
  A a; // [rsp+20h] [rbp-18h] BYREF
  A b; // [rsp+24h] [rbp-14h] BYREF

  A::A(&a);
  A::foo(&a);
  A::A(&b);
  b.var = a.var;
  A::foo(&b);
  return 0;
}

void __fastcall A::A(A *this)
{
  this->var = 100;
}

void __fastcall A::foo(A *this)
{
  printf("hello %d\n", (unsigned int)this->var);
}

스택에 a, b 각 4바이트씩 할당함 (멤버변수 사이즈)

클래스의 함수는 일반적인 함수로 취급 (함수명이 A::foo)

= 연산자에서 대입이 발생

테스트 2

private 변수만 늘리고 컴파일

private:
    int var = 100;
    int var2 = 200;
    int var3 = 300;

아래는 IDA 디컴파일

int __fastcall main(int argc, const char **argv, const char **envp)
{
  A a; // [rsp+20h] [rbp-48h] BYREF
  A b; // [rsp+30h] [rbp-38h] BYREF

  A::A(&a);
  A::foo(&a);
  A::A(&b);
  qmemcpy(&b, &a, sizeof(b));
  A::foo(&b);
  return 0;
}

멤버 변수가 많으면 memcpy로 복사함

테스트 3

class A
{
public:
    A& operator=(const A& a)
    {
        this->var = a.var;
        return *this;
    }
    void foo()
    {
        printf("hello %d\n", var);
    }
    void set(int a)
    {
        this->var = a;
  
    }
private:
    int var = 100;
};

아래는 IDA 디컴파일

int __fastcall main(int argc, const char **argv, const char **envp)
{
  A a; // [rsp+20h] [rbp-18h] BYREF
  A b; // [rsp+24h] [rbp-14h] BYREF

  A::A(&a);
  A::foo(&a);
  A::A(&b);
  A::operator=(&b, &a);
  A::foo(&b);
  return 0;
}

A *__fastcall A::operator=(A *this, const A *a)
{
  this->var = a->var;
  return this;
}

기본 = 연산자가 내가 재정의한 operator=로 대체됨

operator=는 일반적인 함수로 취급 (함수명이 A::operator=)

테스트 4

class A
{
public:
    A& daeip(const A& a)
    {
        this->var = a.var;
        return *this;
    }
    A& operator=(const A& a)
    {
        this->var = a.var;
        return *this;
    }
    void foo()
    {
        printf("hello %d\n", var);
    }
    void set(int a)
    {
        this->var = a;
  
    }
private:
    int var = 100;
};
int main()
{
    A a;
    a.foo();
    A b;
    b = a;
    b.foo();
    A c;
    c.daeip(a);
 }

아래는 IDA 디컴파일

int __fastcall main(int argc, const char **argv, const char **envp)
{
  A a; // [rsp+20h] [rbp-28h] BYREF
  A b; // [rsp+24h] [rbp-24h] BYREF
  A c; // [rsp+28h] [rbp-20h] BYREF

  A::A(&a);
  A::foo(&a);
  A::A(&b);
  A::daeip(&b, &a);
  A::foo(&b);
  A::A(&c);
  A::daeip(&c, &a);
  return 0;
}

daeip 함수와 operator=는 기능적으로 동일함

최적화에 의해 operator= 가 삭제되고 daeip 함수로 통일됨

테스트 5

class A
{
public:
    void daeip(const A& a)
    {
        this->var = a.var;
    }
    void operator=(const A& a)
    {
        this->var = a.var;
    }
    void foo()
    {
        printf("hello %d\n", var);
    }
    void set(int a)
    {
        this->var = a;
  
    }
private:
    int var = 100;
};

int main()
{
    A a;
    a.foo();
    A b;
    b = a;
    b.foo();
    A c;
    c.daeip(a);
}

아래는 IDA 디컴파일

int __fastcall main(int argc, const char **argv, const char **envp)
{
  A a; // [rsp+20h] [rbp-28h] BYREF
  A b; // [rsp+24h] [rbp-24h] BYREF
  A c; // [rsp+28h] [rbp-20h] BYREF

  A::A(&a);
  A::foo(&a);
  A::A(&b);
  A::daeip(&b, &a);
  A::foo(&b);
  A::A(&c);
  A::daeip(&c, &a);
  return 0;
}

b = a 처럼 단순 대입만 할 경우 operator=의 리턴값을 void로 해도 무방하다.

테스트6

class A
{
public:  
    void foo()
    {
        printf("hello %d\n", var);
    }
    void set(int a)
    {
        this->var = a;  
    }
private:
    int var = 100;
};

int main()
{
    A a;
    a.foo();
    A& b = a;
    b.foo();
}

아래는 IDA 디컴파일

int __fastcall main(int argc, const char **argv, const char **envp)
{
  A a; // [rsp+28h] [rbp-20h] BYREF

  A::A(&a);
  A::foo(&a);
  A::foo(&a);
  return 0;
}

A& b를 A a로 인식함

테스트7

class A
{
public: 
    A& operator=(const A& a)
    {
        this->var = a.var;
        return *this;
    }
    void foo()
    {
        printf("hello %d\n", var);
    }
    void set(int a)
    {
        this->var = a;  
    }
private:
    int var = 100;
};

아래는 IDA 디컴파일

int __fastcall main(int argc, const char **argv, const char **envp)
{
  A a; // [rsp+28h] [rbp-20h] BYREF

  A::A(&a);
  A::foo(&a);
  A::foo(&a);
  return 0;
}

재정의를 해도 참조 연산 기능이 동일하여  바이너리 결과는 같음

 

	string a = "hello man world girl";

	cout << static_cast<void*>(a.data()) << endl;
	cout << a << endl;

	string b = a;
	cout << static_cast<void*>(b.data()) << endl;
	cout << b << endl;

	string c = move(a);
	cout << a << endl;
   	cout << static_cast<void*>(a.data()) << endl;
	cout << static_cast<void*>(c.data()) << endl;
	cout << c << endl;

b = a을 하게 되면 복사가 일어난다. 즉, 객체의 생성 -> 복사 -> 파괴가 두번 발생한다.

move 의 경우, 객체의 생성 후 이동만 발생한다. a의 allocator가 c로 이동되며, 이동 후 a의 allocator에는 빈 값과 빈 버퍼가 들어간다. 

 

 

'Windows > Dev' 카테고리의 다른 글

windows + mac 동시 개발 시 주의 사항  (0) 2024.10.15
[MSVC] 클래스 고찰 & 디컴파일  (0) 2024.08.08
detours 빌드 및 적용  (0) 2024.04.11
[Visual Studio 2022] curl 빌드  (0) 2023.01.30
[VC++] string deallocate  (0) 2022.05.23

+ Recent posts