32비트 정수 값: 0x12345678을 메모리에 저장할 때:
| 메모리 주소 | 값 |
| 0x00 | 78 |
| 0x01 | 56 |
| 0x02 | 34 |
| 0x03 | 12 |
→ 실제 메모리: 78 56 34 12
32비트 정수 값: 0x12345678을 메모리에 저장할 때:
| 메모리 주소 | 값 |
| 0x00 | 12 |
| 0x01 | 34 |
| 0x02 | 56 |
| 0x03 | 78 |
→ 실제 메모리: 12 34 56 78
| 구분 | 리틀 엔디언 (Little Endian) | 빅 엔디언 (Big Endian) |
| 데이터 저장 순서 | 하위 바이트부터 | 상위 바이트부터 |
| 메모리 가독성 | 사람이 보기에는 덜 직관적 | 사람이 보기 쉽고 직관적 |
| 사용 환경 | Intel, Windows, ARM 등 | 네트워크 통신, IBM 등 |
| 장점 | 연산 효율성(간단한 CPU 설계) | 네트워크 전송 시 직관적 |
| 단점 | 데이터 가독성 낮음 | CPU 연산 설계 복잡성 증가 |
악성코드 분석 시, 특히 역공학(리버싱, Reversing) 과정에서 메모리 덤프나 바이너리 데이터 분석 시 반드시 엔디언 방식을 고려해야 함.
윈도우 운영체제의 메모리 구조는 크게 사용자 모드(User Mode)와 커널 모드(Kernel Mode)로 나눠짐.
악성코드 분석 시 코드 인젝션, 프로세스 할로잉, 루트킷 등 메모리 기반 공격의 이해에 필수적임.
1+---------------------+ 0xFFFFFFFF
2| 커널 공간 |
3+---------------------+ 0x80000000 (2GB)
4| 사용자 공간 |
5+---------------------+ 0x000000001+----------------------------+ 0xFFFF'FFFFFFFF'FFFF
2| 커널 공간 |
3| |
4+----------------------------+ 0xFFFF'80000000'0000
5| 미사용 공간 |
6+----------------------------+ 0x0000'7FFFFFFF'FFFF
7| 사용자 공간 |
8| |
9+----------------------------+ 0x0000'00000000'0000| 분석 항목 | 32비트 | 64비트 |
| 메모리 주소 분석 | 간단함 (낮은 주소 범위) | 주소 범위 큼 → 분석 어려움 |
| 루트킷 분석 | 제한적 | 64비트는 드라이버 서명, PatchGuard로 보안 ↑ |
| 디버깅 도구 | 32비트 전용 | 64비트 환경 별도 도구 필요 |
1int sum(int a, int b); // b 먼저 push, 그 다음 aRCX, RDX, R8, R9
1void foo(int a, int b, int c, int d, int e);
2→ RCX=a, RDX=b, R8=c, R9=d, [stack]=e정리 !
<32비트 호출 규약>
| 규약 | 인자 전달 | 스택 정리 주체 | 특징 |
| cdecl | 스택 (Right → Left) | 호출자 | C 함수 기본 |
| stdcall | 스택 | 피호출자 | WinAPI |
| fastcall | 레지스터 + 스택 | 피호출자 | 속도 ↑ |
<64비트 호출 규약>
| OS | 규약(표준) | 인자 레지스터 순서 | 추가 인자 | 스택 정리 |
| Windows | Microsoft x64 calling convention | RCX, RDX, R8, R9 | 스택 | 호출자 |
| Linux | System V AMD64 ABI | RDI, RSI, RDX, RCX, R8, R9 | 스택 | 호출자 |
예:
1push 4
2push 2
3call sub_401000→ 스택 두 개 쌓고 함수 호출 → cdecl일 확률 높음
→ 인자 2개 전달 → sub_401000(a=2, b=4) 이런 함수일 수 있겠다(추정)
예:
1call sub_401000
2add esp, 8 ; // caller가 스택 정리 중 → cdecl임인자가 RCX, RDX, R8, R9에 들어가는지 확인해야
→ 함수가 실제 어떤 파라미터로 실행되는지 알 수 있음
예:
1mov rcx, rax // lpApplicationName
2mov rdx, rsp+30h // lpCommandLine
3call CreateProcessW→ RCX/RDX = 첫 두 인자 → Windows x64 호출 규약임 → API 인자 추정 가능
예: push ebp → mov ebp, esp로 시작하면 cdecl이나 stdcall일 가능성 높음
함수를 분석할 때, 그 함수가 무슨 역할을 하고, 무슨 데이터를 가지고, 어디에 영향을 주는지를 이해하려면 호출 규약을 알아야 함
즉, 호출 규약은 함수 분석의 기본 프레임이고,
그걸 알아야 악성 행위의 흐름을 정확하게 추적 → 해석 → 대응할 수 있음






strcmp() 에서 같은 string이면 ‘0’이 return 되어야 하는데 왜 인자가 같으면 ‘1’을 반환한다고 했을까?
| 값 | 의미 |
| 0보다 작음 | string1이 string2보다 작음 |
| 0 | string1이 string2와 같음 |
| 0보다 큼 | string1이 string2보다 큼 |
>> return strcmp(같으면 0 반환함) == 0 ; // 두 string이 같으면 함수 전체적으로 ‘1’을 return 함
>> c언어에서는 strcmp()==0 패턴이 표준처럼 자주 쓰인다고 함










XOR 역연산
1data[i] = (a1[i] * i + 2 * i)
2 = i * (a1[i] + 2)1a1[i] = (data[i] - 2 * i) / i나눗셈을 포함한 식이기 때문에 파이썬에서는 오버플로우 보정을 해주어야 함.
1for i in range(24):
2 tmp = data[i] - 2 * i
3 tmp = tmp % 256 # 오버플로우 보정 (unsigned 8-bit)
4 a1_i = tmp ^ i # XOR 역연산
5 result.append(a1_i)XOR는 한번 더 XOR 하면 원래대로 돌아가기에 역연산에 유리 !
1A ^ B = C
2→ C ^ B = A
3→ C ^ A = B
역연산에 자주 등장하는 구조들
| 유형 | 예시 | 역연산 방식 |
| 직접 비교 | if (a[i] != 100) | ASCII 해석 |
| XOR | a[i] ^ 0xAB == b[i] | 다시 XOR |
| 덧셈/뺄셈 | a[i] + 3 == b[i] | a[i] = b[i] - 3 |
| 로테이션 (bit rotation) | ROR(a[i], 3) | ROL(b[i], 3) |
| 해시 기반 (SHA1 등) | hash(input) == target | 역연산 어려움, 브루트포스 필요 |
| 암호화 (AES 등) | 암호 알고리즘에 의한 비교 | 키 없이는 거의 불가능, 공격 필요 |