本人发现一个新问题!不知道大家以前发现过没有!来一起探讨下!(0分)

  • 主题发起人 主题发起人 tigerhacker
  • 开始时间 开始时间
T

tigerhacker

Unregistered / Unconfirmed
GUEST, unregistred user!
#include <stdio.h>
void main()
{
int a[2],b[2];
b[1]=4;
printf("%d",a[-1]);
}
//猜猜该代码会不会编译通过,如果可以,那么输出结果是什么?
对于这种代码!delphi同样存在这个问题!有意思!
 
#include <stdio.h>
void main()
{
int b[2],a[2];
b[1]=4;
printf("%d",a[-1]);
}
//猜猜该代码会不会编译通过,如果可以,那么输出结果是什么?
 
转成Delphi的
var b,a:array[2] of integer;
begin
b[1]:=4;
showmessage(format('%d',[a[-1]]));
end;

应该是4把,就是b[1]的数据:
存放是 b[0] b[1] a[0] a[1]
a是指针,a[x]后面的数组下标x相当于 @a + x
所以 a[-1] 是 a的地址前一个Integer型数据。
 
诶,通过不了...
改 var b,a:array[0..1] of integer;
,结果
E1012 Constant expression violates subrange bounds
范围错误...(Delphi2006 能检查出来...)
 
木桩,
说的是正确的!我也研究过了!不过呢,我在想的是如果可以这样,那么我们如果拿到一个exe程序
就可以覆盖原代码的数据和读出原代码的数据了!
 
其实不同编译器产生的代码不同,想靠这个溢出覆盖后面的部分,麻烦得很。
刚刚试了一下,实际上那段代码在Delphi里根本就不指向b[1] (假设能运行)
Delphi的顺序和C正好相反,定义 var b,a:array[0..1] of integer;
结果内存里实际存放为:
... a[0] a[1] b[0] b[1] ... (这样a[-1]就是之前的一个变量了)
用这段代码可以证明:
//读取内存的函数
procedure Mem(Address:Pointer;Var Buf;bLength:Cardinal);
Var cBuf:array of byte absolute Buf;
//强制Buf为Byte数组
asm
mov edx,cBuf //取 Buf 地址
mov ebx,Address //写目标地址到ebx
mov ecx,bLength
@re:
mov al,[ebx]
mov [edx],al
inc ebx
inc edx
dec ecx
jnz @re //没完的话,继续
end;

procedure TForm1.Button1Click(Sender: TObject);
var Bufs:array[0..15] of Byte;
b,a:array[0..1] of integer;
begin
b[0]:=$10;
b[1]:=$40;
a[0]:=$A0;
a[1]:=$80;
mem(@a,Bufs,15);
Showmessage(Format('a[0] = %0.2x%0.2x%0.2x%0.2x'
+#13#10+'a[1] = %0.2x%0.2x%0.2x%0.2x'
+#13#10+'b[0] = %0.2x%0.2x%0.2x%0.2x'
+#13#10+'b[1] = %0.2x%0.2x%0.2x%0.2x',
[Bufs[3],Bufs[2],Bufs[1],Bufs[0],
Bufs[7],Bufs[6],Bufs[5],Bufs[4],
Bufs[11],Bufs[10],Bufs[9],Bufs[8],
Bufs[15],Bufs[14],Bufs[13],Bufs[12]]));
a[0]:=a[1]+b[0]+b[1];
//这里要干点什么,不然Delphi发现你后面没用到a,b,用mem()前就释放空间了。
end;
 
对于C语言,我实验过了,后定义的变量的地址要偏前些
比如,在我的电脑上面
int a[5],b[4],c[3],d;
那么 &a=1310572
&b=1310556
&c=1310544
&d=1310540
如果是 int d,c[3],b[4],a[5];
那么 &a=1310540
&b=1310560
&c=1310576
&d=1310588
我的想法是:对于C语言,变量的内存分配是这样的:编译器编译源文件的时候,先把变量名字压栈,等分配内存的时候再弹栈一个一个的分配内存,不知道是这样么!
 
再看看这两段代码,我觉得没办法理解问什么
//***********************************************************
#include <stdio.h>
void main()
{
int a[4],b[4],c[8],i;
for (i=0;i<4;i++)
代码:
{
a=i;
b=2*i;
}
printf("a=");
for (i=0;i<4;i++)
printf("%d,",a);
printf("/nb=");
for (i=0;i<4;i++)
printf("%d,",b);
for (i=8;i<16;i++)
c=100;
printf("/na=");
for (i=0;i<4;i++)
printf("%d,",a);
printf("/nb=");
for (i=0;i<4;i++)
printf("%d,",b);
printf("/n&a[0]=%d/n&b[0]=%d/n&c[0]=%d/n&i=%d/n",&a,&b,&c,&i);
for (i=8;i<16;i++)
printf("/n&c[%d]=%d",i,&c);
}
这段代码输出:(a,b的值被覆盖)
a=0,1,2,3,
b=0,2,4,6,
a=100,100,100,100
b=100,100,100,100
&a[0]=1310576
&b[0]=1310560
&c[0]=1310528
&i=1310524
&c[8]=1310560
&c[9]=1310564
&c[10]=1310568
&c[11]=1310572
&c[12]=1310576
&c[13]=1310580
&c[14]=1310584
&c[15]=1310588
//******************************************************************
#include <stdio.h>
void main()
{
int a[4],b[4],i,c[8];
for (i=0;i<4;i++)
{
a=i;
b=2*i;
}
printf("a=");
for (i=0;i<4;i++)
printf("%d,",a);
printf("/nb=");
for (i=0;i<4;i++)
printf("%d,",b);
for (i=8;i<16;i++)
c=100;
printf("/na=");
for (i=0;i<4;i++)
printf("%d,",a);
printf("/nb=");
for (i=0;i<4;i++)
printf("%d,",b);
printf("/na[0]=%d/nb[0]=%d/nc[0]=%d/ni=%d/n",&a,&b,&c,&i);
for (i=8;i<16;i++)
printf("/n&c[%d]=%d",i,&c);
}
//对于这段代码,和第一段代码就只把 int a[4],b[4],c[8],i;变成 int a[4],b[4],i,c[8];
输出结果为:(a,b的值没有被覆盖)
a=0,1,2,3,
b=0,2,4,6,
a=0,1,2,3,
b=0,2,4,6,
&a[0]=1310576
&b[0]=1310560
&c[0]=1310524
&i=1310556
&c[8]=1310556
&c[9]=1310560
&c[10]=1310564
&c[11]=1310568
&c[12]=1310572
&c[13]=1310576
&c[14]=1310580
&c[15]=1310584
 
后定义的变量的地址要偏前些 C就是这样的,不用怀疑,就是你说得那样,
好像只有Pascal是反的,这是编译器不同的问题。所以你说的 “拿到一个exe程序...” 还要分情况来处理覆盖位置,麻烦而且很难实现吧,至少Delphi2006里,很多溢出覆盖法用不上了。
从第一段代码看出
&c[8]=1310560 正好是 &b[0]=1310560 的位置,所以 往 c[8] ~ c[16]里写东西,覆盖a,b也不奇怪。
而代码2的关键,在于&c[8]=1310556 是 &i=1310556
写c[8]就相当于写i,这样明白了吗?看看
for (i=8;i<16;i++)
结果第一次循环就令 i=100;
//c[8]=100
这样自然跳出了,从而没有覆盖a,b
 
你可以打印一下C[8]~C[15],你就觉得奇怪了!还可以打印一下i;
 
不好意思,刚才拿着半截就开跑,现在知道为什么了,谢谢你,呵呵!~~
能留下你的QQ吗?我个人比较喜欢DELPHI和C,!
 
我一般不上QQ的,要的话也给你 443101052
要不还是邮件交流吧 graves@126.com
ps:我只用Delphi
 
看的出来是个老手了,我一般是用delphi写点软件!c语言做点技术测试什么的!
我加你的QQ!
 
后退
顶部