首页 > 程序开发 > 软件开发 > C# > 正文
C#开发之不为人知的秘密 缓冲区溢出
2017-02-16 10:32:00       个评论    来源:jsd2root的博客  
收藏    我要投稿

C#开发之不为人知的秘密 缓冲区溢出:我们知道,当数组下标越界时,.NET会自动抛出StackOverflowException,这样便让我们可以安全的读写内存,那么我们有没有逾越这个自动检测的屏障。

达到我们非常操作的目的呢?答案是有的,而且我们可以修改一些关键变量如if、switch的判断值,for循环变量i值,甚至方法返回值,当然理论上还可以注入代码、转移代码执行区块,前提是必须在unsafe代码里。

方法在被调用时,系统会进行以下几项操作:将该方法入栈、参数入栈、返回地址入栈、控制代码区入栈(EIP入栈)。我们想要访问方法的栈内地址,常规的托管代码是不行的,只能使用unsafe代码,但也并不是说你非要精通C/C++语言和指针操作,本文的例子都非常简单,完全可以将指针就认为是简版C#数组。

改变临时变量的值

先给出一段代码,然后再详细解释原理。

 

代码

staticunsafevoidMain(string[] args)

{

//在栈上申请一个只能保存一个int32的内存段

int*p=stackallocint[1];

for(var i=0; i<30; i++)

{

System.Threading.Thread.Sleep(200);

Console.WriteLine("{0}\n", i);

p[i]=0;

}

Console.ReadLine();

}

这是一个既简单,但是对于从没有尝试这样写过代码的开发者来说,又颇耐人寻味,C#(包括C/C++)不会去检查指针p的偏移量是否越界,那么这段代码将会顺利编译并运行,那么for循环会顺利执行30次吗?还是......

结论是,这将是一个死循环,因为p不断的递增1偏移,并将附近的内存的值全改为0,而局部变量i是靠p最近的变量,所有当p[i]的偏移地址等于i的地址时,代码p[i]=0就等价于i=0,实际上我在测试中i=6的时候i的值就被覆盖为0了,我在代码中添加了Thread.Sleep(200)和Console.WriteLine("{0}\n", i)就是让大家能更直观的看到程序的执行过程,当然这里也可以改为p[i]=1,p[i]=2等数字

搜索内存值并修改

还是先给出代码
代码

staticunsafevoidMain(string[] args)

{

Console.WriteLine(Change_Result());

Console.ReadLine();

}

staticunsafeintChange_Result()

{

inti=0;

//变量result,默认的返回值

intresult=123;

//申请一段栈内存,大小可随意设置

int*p=stackallocint[1];

//从当前栈地址开始向下查找与函数返回值相匹配的地址,一旦匹配则修改为10000

while(true)

{

if(p[++i]==123)

{

p[i]=10000;

break;

}

};

returnresult;

}

变量result作为方法的返回值默认为123,并且没有任何显式修改其值的代码,关键在这里

while (true)

{

if (p[++i] == 123)

{

p[i] = 10000;

break;

}

}

这段代码找到值为123的内存地址(也就可能是变量result的地址),然后将其值修改为10000,当然,函数返回值就肯定不会再是原先的123咯

这就是经典的StackOverFlow的两个例子,希望通俗易懂能让大家所接受,另外缓冲区溢出并不只是改变内存的值,在高手的手里,他还可以执行任意代码,因为方法执行的时候总会有一个指针指向方法即将执行的下一条指令,如果控制了这个指针,就控制了进程。

点击复制链接 与好友分享!回本站首页
上一篇:C#客户端WinForm与服务器端控制台应用程序之间的联通调试
下一篇:C#中的is和as操作符
相关文章
图文推荐
文章
推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做实用的IT技术学习网站