Skip to content

Instantly share code, notes, and snippets.

@hwhw
Last active December 25, 2019 19:58
Show Gist options
  • Save hwhw/814a17a5cdbccc26ca558726aa83c5aa to your computer and use it in GitHub Desktop.
Save hwhw/814a17a5cdbccc26ca558726aa83c5aa to your computer and use it in GitHub Desktop.
Pixelblaster_v6 by @HIlse
--[[
Pixelblaster_v6 by @hilse
Needs LuaJIT & ljsyscall (syscall.lua & syscall/...)
and lodepng
This is a perfect example on how to not do things correctly while still using Lua.
Run this with enough rights to send raw packets
Usage:
24bpp RGB from stdin (optionally, a continuous stream):
luajit flut.lua <interface> <our MAC> <our IPv6> <target/router MAC> <target IPv6> <xoffs> <yoffs> <width> <height> [cont]
PNG (alpha aware):
luajit flut.lua <interface> <our MAC> <our IPv6> <target/router MAC> <target IPv6> <xoffs> <yoffs> image.png
License: WAGTD 1.0
§1: We're all going to die.
Changelog:
- now supports PNG & Alpha
- IPv6 now without any payload at all: 54 byte on ethernet layer - a whopping 12% increase in productivity!
--]]
local ffi=require"ffi"
local bit=require"bit"
local S=require"syscall"
ffi.cdef"unsigned int lodepng_decode32_file(unsigned char **, unsigned int *, unsigned int *, const char *);"
-- compile lodepng: gcc -shared -fPIC -o lodepng.so -c lodepng.c
local lodepng=ffi.load("./lodepng.so")
-- mwahahahahaha!
local s = S.socket(S.c.AF.PACKET,S.c.SOCK.RAW,S.c.IPPROTO.RAW)
-- interface index
local if_idx = S.util.if_nametoindex(arg[1],s)
local sll_dest = S.t.sockaddr_ll{ifindex=if_idx, addr=S.t.macaddr(arg[4])}
-- we build ourselves a nice and shiny package
local sbuf_l = 54
local sbuf = ffi.new("uint8_t[?]", sbuf_l)
ffi.copy(sbuf, sll_dest.addr, 6)
ffi.copy(sbuf + 6, S.t.macaddr(arg[2]), 6)
sbuf[12]=0x86
sbuf[13]=0xDD
sbuf[14]=0x60
sbuf[15]=0
sbuf[16]=0x48 -- H
sbuf[17]=0x57 -- W
sbuf[18]=0 -- packet length
sbuf[19]=0 -- packet length
sbuf[20]=59 -- next header: UDP
sbuf[21]=0xFF -- hop limit
ffi.copy(sbuf+22, S.t.in6_addr(arg[3]), 16)
ffi.copy(sbuf+38, S.t.in6_addr(arg[5]), 16)
local function set_px(x, y, r, g, b, a)
sbuf[46] = bit.rshift(x, 8)
sbuf[47] = bit.band(x, 255)
sbuf[48] = bit.rshift(y, 8)
sbuf[49] = bit.band(y, 255)
sbuf[50] = r
sbuf[51] = g
sbuf[52] = b
sbuf[53] = a
S.sendto(s, sbuf, sbuf_l, 0, sll_dest, ffi.sizeof(sll_dest))
end
local dx=arg[6]
local dy=arg[7]
local w, h
local pic
local lframe = function() end
local bpp = 24
if tonumber(arg[8]) and tonumber(arg[8]) > 0 then
w=arg[8]
h=arg[9]
-- read data from... stdin
pic=ffi.new("uint8_t[?]", w*h*3)
-- read one frame:
lframe = function()
local r = w*h*3
local d = 0
while true do
if(d == r) then return end
local res = S.read(0, pic+d, r-d)
if(res > 0) then
d = d + res
end
end
end
lframe()
else
bpp=32
pic=ffi.new("uint8_t*[1]")
w = ffi.new("unsigned int[1]")
h = ffi.new("unsigned int[1]")
local err=lodepng.lodepng_decode32_file(pic, w, h, arg[8])
if err>0 then
print("error opening file:", err)
os.exit(1)
end
w = w[0]
h = h[0]
pic = pic[0]
end
local function get_px(x, y)
local c
local a
if bpp==24 then
c = (y*w+x)*3
a = 255
elseif bpp==32 then
c = (y*w+x)*4
a = pic[c+3]
end
return pic[c], pic[c+1], pic[c+2], a
end
local t=ffi.new("uint32_t[?]", w*h)
local act_px = w*h
local c=0
for y=0,h-1 do
for x=0,w-1 do
local r,g,b,a = get_px(x, y)
if a==0 then
act_px = act_px - 1
else
t[c]=bit.bor(bit.lshift(y, 16), x)
c=c+1
end
end
end
-- Fisher - Yates shuffle:
math.randomseed(os.time())
for i=act_px, 1, -1 do
local j=math.random(i)
t[i], t[j] = t[j], t[i]
end
-- one loop:
local function play()
-- send pic
for p=0,act_px-1 do
local x = bit.band(t[p], 0xffff)
local y = bit.rshift(t[p], 16)
local r,g,b,a = get_px(x, y)
if a > 0 then
set_px(dx+x, dy+y, r,g,b,a)
end
end
if arg[10] == "cont" then
-- continuous reading (e.g. from ffmpeg)
lframe()
end
end
while true do
play()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment