查看文章 |
先看一小段代码: void test_a() { int a = 1; __asm mov [ebp-4],8 int b =a; int c = a; printff("--%d %d\n",b,c); } 在 DBUGE和RELEASE模式下编译这段代码,可以发现运行结果并不一样, 查看反汇编代码后,应该会发现问题, 那么在RELEASE模式下,int a = 1; 改为 volatile int a = 1; 再运行下看结果。
再看 int ig_a = 0; int ig_b = 8; void xxx(volatile int* x) { printf("--%d\n",*x); }
void main() { int* iptr = (int*)&ig_a; int il_a = 1; __asm mov [ebp - 4],11 printf("--%d\n", il_a); xxx( iptr ); } 在 DBUGE和RELEASE模式下编译这段代码,可以发现运行结果一样 大家都知道 __asm mov [ebp - 4],11 句话话的意思吧, 就是给第一个参数的值赋值为11 C中,先声明的变量的地址比较高,所以[EBP-4]应该是 指 IPTR变量,但实际上 __asm mov [ebp - 4],11 在这里并不起到任何作用,很奇怪吧。 int il_a = 1; 改为 volatile int il_a = 1.。。再看看结果,奇怪吧。。
有时候我们写程序的逻辑编译器并不等于跟我们想的一样,特别是使用编译优化的时候。 比如 void res() { static int count = 0; count = count+2;
//// 一些不会操作到 count 的代码 ////// QQQQQQQQQQQQQQQQQQQQ
count = count+2;
printf("--%d\n",count);
} 我们会以为这个输出是4,是的,从程序上看的确是4, 但是,如果你采用 RELEASE发行你的程序,并且这个函数会被多个线程掉用,那可能会有点问题。 反汇编看下
; 93 : static int count = 1; ; 94 : count = count+2; ; 95 : ; 96 : //// 一些不会操作到 count 的代码 ; 97 : ; 98 : ; 99 : count = count+2;
mov eax, DWORD PTR _?count@?1??res@@YAXXZ@4HA add eax, 4
; 100 : ; 101 : printf("--%d\n",count);
push eax push OFFSET FLAT:??_C@_05GJKK@?9?9?$CFd?6?$AA@ ; `string' mov DWORD PTR _?count@?1??res@@YAXXZ@4HA, eax call _printf add esp, 8 好,我们知道 count的值最终放在寄存器 eax (add eax, 4) 假如执行到 add eax, 4,发生了中断, 线程调度程序 终止当前线程的执行,保存当前线程的上下文,注意,EAX ==4被保存了, 接着调度程序调用另一线程执行, 另一线程也 调用了 res()函数, count的值变了,因为是static int count,理论上这时候的值应该是 8,因为前面加4了嘛。假设线程也执行到 add eax, 4 被中止,这时候原来的线程被恢复执行,调用 printf("--%d\n",count); 结果输出是4,你会说,不对啊。。呵呵,对的, 因为 count的进行计算后的值是放到了 eax中,寄存器是线程相关的,所以count为静态变量而且即使其他线程也改了count,但原线程的输出还是4,并不会变换
总结: 在逆向,或者在驱动中编写的变量的值是可被改写的, 而且访问这些变量的函数时可以被多个线程调用的,应该要注意这种情况,一般时候我们不能老依赖编译器的优化,解决可以用 volatile 来定义变量,volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了,直接按地址访问,而不是寄存器,因为寄存器是线程相关,在多线程的环境下可能造成同步问题。
|