반응형
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | // compiled with : gcc -o memcpy memcpy.c -m32 -lm #include <stdio.h> #include <string.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <sys/mman.h> #include <math.h> unsigned long long rdtsc(){ asm("rdtsc"); } char* slow_memcpy(char* dest, const char* src, size_t len){ int i; for (i=0; i<len; i++) { dest[i] = src[i]; } return dest; } char* fast_memcpy(char* dest, const char* src, size_t len){ size_t i; // 64-byte block fast copy if(len >= 64){ i = len / 64; len &= (64-1); while(i-- > 0){ __asm__ __volatile__ ( "movdqa (%0), %%xmm0\n" "movdqa 16(%0), %%xmm1\n" "movdqa 32(%0), %%xmm2\n" "movdqa 48(%0), %%xmm3\n" "movntps %%xmm0, (%1)\n" "movntps %%xmm1, 16(%1)\n" "movntps %%xmm2, 32(%1)\n" "movntps %%xmm3, 48(%1)\n" ::"r"(src),"r"(dest):"memory"); dest += 64; src += 64; } } // byte-to-byte slow copy if(len) slow_memcpy(dest, src, len); return dest; } int main(void){ setvbuf(stdout, 0, _IONBF, 0); setvbuf(stdin, 0, _IOLBF, 0); printf("Hey, I have a boring assignment for CS class.. :(\n"); printf("The assignment is simple.\n"); printf("-----------------------------------------------------\n"); printf("- What is the best implementation of memcpy? -\n"); printf("- 1. implement your own slow/fast version of memcpy -\n"); printf("- 2. compare them with various size of data -\n"); printf("- 3. conclude your experiment and submit report -\n"); printf("-----------------------------------------------------\n"); printf("This time, just help me out with my experiment and get flag\n"); printf("No fancy hacking, I promise :D\n"); unsigned long long t1, t2; int e; char* src; char* dest; unsigned int low, high; unsigned int size; // allocate memory char* cache1 = mmap(0, 0x4000, 7, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); char* cache2 = mmap(0, 0x4000, 7, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); src = mmap(0, 0x2000, 7, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); size_t sizes[10]; int i=0; // setup experiment parameters for(e=4; e<14; e++){ // 2^13 = 8K low = pow(2,e-1); high = pow(2,e); printf("specify the memcpy amount between %d ~ %d : ", low, high); scanf("%d", &size); if( size < low || size > high ){ printf("don't mess with the experiment.\n"); exit(0); } sizes[i++] = size; } sleep(1); printf("ok, lets run the experiment with your configuration\n"); sleep(1); // run experiment for(i=0; i<10; i++){ size = sizes[i]; printf("experiment %d : memcpy with buffer size %d\n", i+1, size); dest = malloc( size ); memcpy(cache1, cache2, 0x4000); // to eliminate cache effect t1 = rdtsc(); slow_memcpy(dest, src, size); // byte-to-byte memcpy t2 = rdtsc(); printf("ellapsed CPU cycles for slow_memcpy : %llu\n", t2-t1); memcpy(cache1, cache2, 0x4000); // to eliminate cache effect t1 = rdtsc(); fast_memcpy(dest, src, size); // block-to-block memcpy t2 = rdtsc(); printf("ellapsed CPU cycles for fast_memcpy : %llu\n", t2-t1); printf("\n"); } printf("thanks for helping my experiment!\n"); printf("flag : ----- erased in this source code -----\n"); return 0; } | cs |
소스코드 맨 위에
// compiled with : gcc -o memcpy memcpy.c -m32 -lm
이런 주석이 달려있다. 주는 이유는 분명 있을 것이다.
우리 VM에서 한 번 해보자.
64비트에서 컴파일 하시는 분은 아래와 같은 오류가 나올 수 있다.
이 에러는
apt-get install g++-multilib libc6-dev-i386
위 명령어로 해결할 수 있다.
그전에 볼 명령어 2개
MOVDQA
- Move Aligned Double Quadword
데이터 전송 명령어로, 128bits의 데이터를 한 번에 xmm 레지스터로 이동하거나, 반대로 xmm레지스터의 데이터를 메모리로 전송하는 처리를 한다.
MOVNTPS
Store Packed Single-Precision Floating-Point Values Using Non-Temporal Hint
두 번째 오퍼랜드로 입력받은 XMM 레지스터에 있는 float형 데이터 4개를 캐시를 통하지 않고 첫 번째 오퍼랜드로 입력받은 메모리 주소로 복사한다.
가장 큰 특징은 weakly-ordered memory consistency model 이라는 겁니다.
ex) MOVNTPS m128, xmm
모두 정렬된이라는 특징을 가지고 있네요. 사실 속도 빠름에 있어서는 메모리 접근에 가장 큰 영향이 있습니다. 참고 !
** 아래 명령어에서 가장 중요한 사실이 있습니다.
the operand must be aligned on a 16-byte boundary or a general-protection exception (#GP) will be generated. <--- 즉 16바이트로 정렬해야 한다. 그렇지 않으면 일반 보호 예외가 발생한다고 한다.
MOVDQA
MOVNTPS
- 코드 설명 -
1 2 3 4 | unsigned long long rdtsc(){ asm("rdtsc"); } | cs |
Read Time-Stamp Counter 라고 한다.
1 2 3 4 5 6 7 8 | char* slow_memcpy(char* dest, const char* src, size_t len){ int i; for (i=0; i<len; i++) { dest[i] = src[i]; } return dest; } | cs |
정말 slow하게 for문으로 하나하나 작업해주네요.
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 | char* fast_memcpy(char* dest, const char* src, size_t len){ size_t i; // 64-byte block fast copy if(len >= 64){ i = len / 64; len &= (64-1); while(i-- > 0){ __asm__ __volatile__ ( "movdqa (%0), %%xmm0\n" "movdqa 16(%0), %%xmm1\n" "movdqa 32(%0), %%xmm2\n" "movdqa 48(%0), %%xmm3\n" "movntps %%xmm0, (%1)\n" "movntps %%xmm1, 16(%1)\n" "movntps %%xmm2, 32(%1)\n" "movntps %%xmm3, 48(%1)\n" ::"r"(src),"r"(dest):"memory"); dest += 64; src += 64; } } // byte-to-byte slow copy if(len) slow_memcpy(dest, src, len); return dest; } | cs |
왜 빠른지는 asm 명령어 설명할 때 하였다. 128bits 정보를 한번에 처리!
다만 아래 if문에서 len이 참이면 slow_memcpy로 가버리네요.
main 소스코드는 천천히 읽어주시면 됩니다… ^^
다시 문제 풀이로 돌아와서
실제 flag를 받고 싶으면 nc 0 9022로 연결해서 해결하라고 합니다. 씌익
설마 flag : erased ~~ 를 인증해보신 분 없으시죠 !?
한 번 프로그램을 실행시켜봅시다.
실험이 10번은 이루어져야 하는데, 5번에서 끝나버리네요 …
위 사진은 최소, 최대를 각각 입력시켜준 것입니다.
최소일 때는 5번 최대일 때는 4번이네요.
하지만 처음에 말했듯이 우리의 VM에서 소스코드를 가져가면
우리 입맛대로 다시 수정할 수 있습니다.
fast_memcpy 다음에 주소가 얼마나 할당되는지 확인해봤습니다.
메모리에서 정렬된 규칙을 가진다라는 큰 힌트를 꼭 생각해봤습니다.
각 숫자마다 각 차이를 구해도 보고, 주소값도 차를 구해서 규칙을 찾아보고.
이것저것 실험해봤습니다. ( 많은 삽질을 하게 됐네요… 이렇게 하는지 맞는가 싶기도 했고 .. )
우선 위 사진을 보면 각 끝나는 주소를 보면 8 or 0 으로 끝나는 것을 찾아볼 수 있었습니다. 실험 1번은 8로 끝나니 실험 2번도 8로 끝내보고자 16값이 아니라 8을 더한 24값을 넣어봤습니다.
그러더니 주소 값의 차이가 16차이가 나네요. 하나만 바꿔서는 위에 보이는 실험 4까지 8로 끝내게 바꾸어봤습니다.
메모리 정렬이 이렇게 되는구나 라고 느끼게 되었습니다.
이제 남은 실험들의 값들에 8을 각각 더해주면 될 것이라고 생각했습니다.
8 24 40 72 136 264 520 1032 2056 4104
순으로 계속 입력했습니다.
1_w4nn4_br34K_th3_m3m0ry_4lignm3nt
피곤하냐며 쉬라고 하더니 이게 뭔일입니까 …. 삽질 삽질 !
반응형
'[ ★ ]Study > War Game' 카테고리의 다른 글
[Toddler's Bottle] pwnable.kr coin1 (0) | 2018.08.12 |
---|---|
[Toddler's Bottle] pwnable.kr unlink 풀이 (0) | 2017.09.17 |
[Toddler's Bottle] pwnable.kr asm 풀이 (0) | 2017.09.16 |
[Toddler's Bottle] pwnable.kr codemap 풀이 (0) | 2017.09.15 |
[Toddler's Bottle] pwnable.kr uaf 풀이 (0) | 2017.09.15 |
댓글