昨晚用Lua实现了一个自动投票机,在此写下思路以供参考:
1.首先查看了投票页的代码,提取到表单如下:
<form name="vote" action="vote.asp?action=save" method="post">
<input NAME="code" ID="code" size="30" maxlength="18">
<input NAME="checkcode" ID="checkcode" size="10" maxlength="6"></td>
<img src="check/Code.asp">
</form>
其中code表单域要输入投票人的身份证号码,checkcode表单域要输入验证码。而Code.asp则负责生成图片验证码,如:
2.通过多次刷新页面,提取验证码样本:
3.使用 SmartSniff 查看到提交的时候POST的数据为 "ik=7&code=320482198506020111&checkcode=pfbzjv"
4.使用 cURL 进行模拟投票的过程为:
访问投票页获得cookie:curl -s -D cookie_vote.txt -o vote.html http://www.test.com/vote.asp?id=6
读取验证码:curl -s -o CheckCode.bmp -D cookie_code.txt -b cookie_vote.txt http://www.test.com/code.asp
提交:curl -d "ik=7&code=身份证号&checkcode=验证码" -b cookie_code.txt -b cookie_vote.txt http://www.test.com/vote.asp?action=save
5.使用Lua自动进行此过程。对验证码图形的处理,采用了与样本依次比较的方法,比较简单嘛。这里由于验证码有效数字都是黑色,其实并没有必要采用阀值处理。
-------------------------------------------------------------------------------
--
-- 自动投票机
--
-- Author Jianglu
-- Version 1.0.0.0
--
-------------------------------------------------------------------------------
-- 使用SDL对图片进行操作
require "sdl"
local SDL = SDL
-- 载入验证码样本
local Stylebook = SDL.SDL_LoadBMP("Stylebook.bmp")
if not Stylebook then
print("Couldn't load Stylebook.bmp : "..SDL.SDL_GetError())
os.exit(1)
end
math.randomseed(os.time())
-------------------------------------------------------------------------------
-- 阀值处理
-------------------------------------------------------------------------------
function SurfaceThreshold(interface, value)
-- 获得灰度值
function GetGrayscale(color)
local r, g, b = SDL.SDL_GetRGB(color, interface.format)
return (30 * r + 59 * g + 11 * b) / 100
end
for x = 0, interface.w - 1 do
for y = 0, interface.h - 1 do
local color = SDL.SDL_GetPixel(interface, x, y)
if GetGrayscale(color) >= value then
SDL.SDL_PutPixel(interface, x, y,
SDL.SDL_MapRGB(interface.format, 255, 255, 255))
end
end
end
end
-------------------------------------------------------------------------------
-- 图块比较
-------------------------------------------------------------------------------
function BlockMatch(interface0, interface1, x0, y0, x1, y1, cx, cy)
for x = 0, cx - 1 do
for y = 0, cy - 1 do
local color0 = SDL.SDL_GetPixel(interface0, x0 + x, y0 + y)
local color1 = SDL.SDL_GetPixel(interface1, x1 + x, y1 + y)
if color0 ~= color1 then return false end
end
end
return true
end
-------------------------------------------------------------------------------
-- 自动生成身份证号
-- 符合国标 GB11643-1999 规定
-------------------------------------------------------------------------------
function GetCardIdentity()
while true do
local id = "32048219"
-- 年 40 ~ 80
id = id .. (40 + math.random(40))
-- 月 math.random(1)
if math.mod(math.random(10), 2) == 1 then
id = id .. "0" .. (1 + math.random(8))
else
id = id .. "1" .. math.random(2)
end
-- 日
id = id .. math.random(2) .. (1 + math.random(8))
-- 三位顺序码
id = id .. math.random(9) .. math.random(9) .. math.random(9)
-- 计算校验码
local sum = 0
local weight = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
for i = 1, 17, 1 do
sum = sum + string.sub(id, i, i) * weight[i]
end
local code = {1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2}
local result = code[math.mod(sum, 11) + 1]
if result ~= 'X' then
return id .. result
end
end
end
-------------------------------------------------------------------------------
-- 识别验证码
-------------------------------------------------------------------------------
function GetCheckCode()
local CheckImage = SDL.SDL_LoadBMP("CheckCode.bmp")
SurfaceThreshold(CheckImage, 1)
SDL.SDL_SaveBMP(CheckImage, "CheckCode2.bmp")
local CheckString = ""
for i = 0, 5, 1 do
local j = 0
while j < 36 do
if BlockMatch(Stylebook, CheckImage,
j * 10, 0, i * 10, 0, 10, 15) then break end
j = j + 1
end
if j < 10 then
CheckString = CheckString .. string.char(48 + j)
else
CheckString = CheckString .. string.char(97 + j - 10)
end
end
CheckImage = nil
return CheckString
end
-------------------------------------------------------------------------------
-- 主投票流程
-------------------------------------------------------------------------------
function Delay(sec)
local Begin = os.clock()
while os.clock() - Begin < sec do end
end
-------------------------------------------------------------------------------
-- 主投票流程
-------------------------------------------------------------------------------
function AutoVote()
local status
-- 重新连接更换IP
print("断开连接 ...")
os.execute("rasdial 宽带连接 /disconnect")
print("进行拨号 ...")
os.execute("rasdial 宽带连接 xxxxx xxxxx")
-- 等待连接
local Try = 0
io.write("开始尝试连接投票页 ")
for Try = 1, 10 do
io.write(". ")
status = os.execute("curl -s -D cookie_vote.txt -o vote.html http://www.test.com/vote.asp?id=7")
if status == 0 then break end
Delay(1000)
end
io.write("\n")
if status ~= 0 then
print("重试10次都无法连接远程主机,重新拨号")
return
end
-- 投票页已经连上
status = os.execute("curl -s -o CheckCode.bmp -D cookie_code.txt -b cookie_vote.txt http://www.test.com/Code.asp")
local Code = GetCheckCode()
local Id = GetCardIdentity()
print("身份证号:" .. Id .. " 验证码:" ..Code)
os.execute([[curl -d "ik=7&code=]] .. Id .. [[&checkcode=]] .. Code .. [[" -b cookie_code.txt -b cookie_vote.txt http://www.test.com/vote.asp?action=save]])
end
-------------------------------------------------------------------------------
-- 就让他无穷循环吧 ...
-------------------------------------------------------------------------------
while true do
AutoVote()
end