Created
October 27, 2009 21:01
-
-
Save s7ephen/219957 to your computer and use it in GitHub Desktop.
user32 from ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# == User32.rb | |
# PoC for how to interface with the User32 subsystem on windows | |
# aka: Control windows and stuff, simulate keyboard/mouse. | |
# This is particularly useful for app pentesting because you can use this | |
# to "enable" disabled menus/buttons etc. | |
# This will demonstrate rudimentary window messaging via the user32 API | |
# to control Calc.exe | |
# | |
# == Author | |
# Stephen A. Ridley | |
# [email protected] | |
# | |
# == The Details | |
# | |
# Use Winspector Pro (a free download) | |
# to observe messages being sent to your windowobject | |
# http://www.windows-spy.com/ | |
# Also use MSDN and the #defines winuser.h to get the numeric | |
# values of some of the SendMessage message opcodes. EG: | |
# http://msdn.microsoft.com/en-us/library/ms646280(VS.85).aspx | |
# I have included a part of some sample C code from an old (now defunct, cuz someone | |
# burned me) private remote Yahoo messenger exploit I've been sitting on. | |
# It is in the DATA block. | |
#-- | |
# ATTENTION ALL YE HIGH-AND-MIGHTY RUBY STYLE CRITICS: | |
# Let me put this in the language you love so much: | |
# if the_code.does_it_work?: You::stfu() end | |
#++ | |
# NOTE TO MYSELF | |
# You cant EnableWindow/SendMessage/SetWindowLong(style) on a button | |
# object that has a windowhook/proc defined. This is why when you | |
# "re-enable" a disabled button it still remains unclickable. To make this | |
# work you need to OpenProcess() and physically modify memory. There might | |
# also be a way to do this with "SetWindowsHookEx()". I will have to look | |
# into how does this. | |
require 'Win32API' | |
require 'irb' | |
require 'optparse' | |
require 'rdoc/usage' | |
require 'zlib' | |
# From winuser.h | |
#http://doc.ddart.net/msdn/header/include/winuser.h.html | |
WM_ENABLE = 0x000A | |
WM_PAINT = 0x000F | |
WM_KEYDOWN = 0x0100 | |
WM_KEYUP = 0x0101 | |
WM_CHAR = 0x0102 | |
WM_USER = 0x0400 | |
WM_LBUTTONDOWN = 0x0201 | |
WM_LBUTTONUP = 0x0202 | |
WM_MOUSEACTIVATE = 0x0021 | |
WM_NCPAINT=0x0085 | |
RDW_INVALIDATE = 0x0001 | |
RDW_INTERNALPAINT = 0x0002 | |
GWL_STYLE = -16 | |
WS_DISABLED = 0x08000000 | |
EnableWindow = Win32API.new("user32", "EnableWindow", 'LL', 'L') | |
SendMessage = Win32API.new("user32","SendMessage", ['L'] * 4, 'L') | |
RedrawWindow = Win32API.new("user32","RedrawWindow", ['L'] * 4, 'L') | |
FindWindowEx = Win32API.new("user32","FindWindowEx", 'LLPP','L') | |
IsWindowEnabled = Win32API.new("user32","IsWindowEnabled",'L','L') | |
UpdateWindow = Win32API.new("user32","UpdateWindow",'L','L') | |
GetWindowLong = Win32API.new("user32", "GetWindowLong", 'LL','L') | |
SetWindowLong = Win32API.new("user32", "SetWindowLong", 'LLL','L') | |
def click_button(sm, button) | |
sm.call(button, 0x0021, 1, 513) | |
sm.call(button,0x0201,0,0x000A0021) | |
sm.call(button,0x202,0,0x000A0021) | |
end | |
# Open our backpack... | |
# Made with: puts [File::open("winuser_test.cpp.gz").read()].pack('u') | |
def displayC() | |
stuff = DATA.read() | |
thingz = stuff.unpack('u') | |
gz = Zlib::GzipReader.new(StringIO.new(thingz.join())) #trick to convert string | |
#to input stream | |
thing = gz.read() | |
puts thing | |
end | |
options={} | |
options[:e] = false | |
opts = OptionParser.new() | |
opts.on("-h", "--help", "You're looking at it."){puts opts.to_s;Kernel.exit(0)} | |
opts.on("-e", "--extract", "Display a C example of user32 interaction."){|blah| options[:e] = true} | |
opts.parse(ARGV) rescue puts opts.to_s | |
if options[:e] then | |
displayC() | |
Kernel.exit(0) | |
end | |
puts "Finding the Start Menu..." | |
sleep(1) | |
startbar = FindWindowEx.call(0,0,"Shell_TrayWnd",0) | |
puts "Finding Start Button..." | |
start_button = FindWindowEx.call(startbar,0,0,"start") | |
click_button(SendMessage, start_button) | |
puts("I cant find what I am looking for there, so I am launching the Calculator.") | |
sleep(1) | |
click_button(SendMessage, start_button) | |
crap = IO.popen('calc.exe') | |
sleep(2) | |
puts("Finding Calculator window...") | |
calculator = FindWindowEx.call(0,0,"SciCalc",0) | |
#edit_area = FindWindowEx.call(notepad,0,0,"Edit") | |
#calc_win = FindWindowEx.call(0,0,0,"Calculator") | |
#= FindWindowEx.call(anchor,0,0,"&Cancel") | |
#ok = FindWindowEx.call(anchor,0,0,"&OK") | |
#password = FindWindowEx.call(0,0,0,"&Password:") | |
#= GetWindowLong.call(GWL_STYLE) | |
#cancel_style |= WS_DISABLED #If the window style does not have WS_DISABLED, this sets it. | |
#SetWindowLong.call(cancel, GWL_STYLE, cancel_style) | |
#EnableWindow(cancel, 0) #This makes the button unclickable but not greyed out. | |
#EnableWindow(cancel,1) #This makes the button clickable again, but doesnt change color. | |
#ok_style = GetWindowLong.call(ok, GWL_STYLE) | |
#ok_style &= ~WS_DISABLED #If the window style has WM_DISABLED this unsets this style. | |
#SetWindowLong.call(ok, GWL_STYLE, ok_style) | |
one = FindWindowEx.call(calculator, 0,0,"1") | |
five = FindWindowEx.call(calculator, 0,0,"5") | |
six = FindWindowEx.call(calculator, 0,0,"6") | |
eight = FindWindowEx.call(calculator, 0,0,"8") | |
two = FindWindowEx.call(calculator, 0,0,"2") | |
times = FindWindowEx.call(calculator, 0,0,"*") | |
plus = FindWindowEx.call(calculator, 0,0,"+") | |
equal = FindWindowEx.call(calculator, 0,0,"=") | |
c = FindWindowEx.call(calculator, 0,0,"C") | |
ce = FindWindowEx.call(calculator, 0,0,"CE") | |
click_button(SendMessage, one) | |
sleep(1) | |
click_button(SendMessage, five) | |
sleep(1) | |
click_button(SendMessage, six) | |
sleep(1) | |
click_button(SendMessage, six) | |
sleep(1) | |
click_button(SendMessage, eight) | |
sleep(1) | |
click_button(SendMessage, times) | |
sleep(1) | |
click_button(SendMessage, two) | |
sleep(1) | |
click_button(SendMessage, plus) | |
sleep(1) | |
click_button(SendMessage, one) | |
sleep(1) | |
click_button(SendMessage, equal) | |
EnableWindow.call(c, 0) | |
EnableWindow.call(ce, 0) | |
puts "Try to click the 'C' or 'CE' buttons..." | |
sleep(5) | |
puts "Ok hit <ENTER> to continue.";gets() | |
EnableWindow.call(c, 1) | |
EnableWindow.call(ce, 1) | |
puts "ok you get the idea...quitting." | |
Kernel.exit(0) | |
__END__ | |
M'XL("(`0YTH``W=I;G5S97)?=&5S="YC<'``G5C]4QI)&OY9J_P?WI#*!5P$ | |
MS6XV=7I)"@$CM0B6C,OMQ90USC1,G\,T.]TCNJG\[_N\W3,PH%Y2ARF=:=[O | |
MSZ?S4B9!G(6"*MJ$_N2^$55VME\6A__"H52-Z$/Y;"&34"WTQNE<^W.Y<2:5 | |
M-JGP9Q^HV2R>26?W99I`S6:!2>,-UK%,,BU2>\H_+T,QD8F@D7?1:WM$![0Z | |
MZW6N3WH7(Z]]VNMWZ&!_OT3>^T^7?MW?Y[.=[6;3BZ0F_/.IW>KWCUOMWZBJ | |
M;NZDRG3\4",3^886@J":)BJE>2H3(Y,IJ<R0'\<@$!3@09-1Q`+Y8)(E@9$J | |
MT8Y_*@P$D#;99$*QO!40HP*A-0RMDS!!W8JZ\;4(226%%$_-J2_N1$QC&V"* | |
M_"2,14EH*DR6)F":I&I&W22;.4I=K;&0'MV(6$*"XRA,O?V;7T"5RH307 | |
M*55BI>85NH%K/0I5P@I`_T"W";0'V5\L%%^E<CZ'4FF<7JUF`I(.*3)F?MAL | |
M:CF;PTS?_F[(9**:.]O'PV%_%>*2J><(1?5T/.A0-$[".O7/6Q>M,XK/_=2? | |
MU>CKSO969SR\Z%"X\"+8$_9`%"[.701[X1$(3GN#D=<:M+L4]1)M_"00?!Q$ | |
M?DHC@Y1-/[]Y^_:+)6T-.GW0Y?Q\)"=4?<'*$;2M+1=3\BXNNT=;6_!WH)!I | |
M<C5>4!\>]K2S_W>IY4TLJI;_>0%WCJS@'XDD/(-Z?^HXZS0^N_[4];SNO[TZ | |
M:?F74).JL[Q6IZJ+22T_>$Y+;B,9::RF92SH/567(:I]$L:9WE?)--?^:=R_ | |
M7E%P4%;1!O>2Q9TM8Y]S_Z.4#LM<1!>LP[E(\K?J^<6PW1V-KE$%UZTV/];I | |
MI-4?==<2:B78/D.D*J>V/`_IU3WM[>U]1D'#:FZV+WC]0*_T55*IYZ63QX?Y | |
MV['2PO%6"VOL%^6X[6Q_XR'PN#3;D8S#56':UR<K$T:2#//O(?K.CXN_;^HD | |
MC\B6(`[T>A7:XW;L:[U1GNR=^X*SD_/?9)///+=^`@W-Q$P+4\59G?;O?SDH | |
MRH6I:D<8082/ZQ@TLE')=3QG@X_67Y&:_7M,P=;^_IN#)]D6ZVR+-3;[.7)< | |
M-D8(BD@,NX#)[B)2+AQ;:WF<N-AZG3Q-N:>.=OFZ)&V/KUO>\,P2%P0#?R8* | |
M@E(,EWU3.JO5B@8O:7I/O_SSX-U;FT'*/Z[>JI6KY,I<F<\_?:$3E24A&M^Y | |
M3YB?^:1\=8^"L^IK1_]+0,L8,9O;98'5\#J(97#[^KMR7!Q=.-QS]1%->7KD | |
M<<#X.!M>CKJMMM?[O>6AHTZ]=K_7'6"<O#WX&871;'Y/0/_XTO.&@\YP/,#, | |
M&;N9LY;]>C&)UDII677?%7UY_IQ@>D:R$_R-1(P%_+79_&^FC8LU+?+5/.%$ | |
M-38S09R*TO"P^<>3AB94`9YDK5)_JHJ6E;+4_LS<8"-FODRHRD]^.L4>YZ?= | |
M73S?N0&!B7KA79[W!B=#E"?2^C4O4BUK5FXQ$YGBXJSE]88#FLMR9ZDLQ6"O | |
M\]_<W.))NP*I%W`BEMK<J/N<V8Z.,)O=^2E.FKML\O"W.O:W7>>&@0\6_JU& | |
M$&4*L5CP5%E$#T2A#.&']M^I5)(-^7(J+@$&P(-%%,Z&G>T'/U+*`0U&0"#3 | |
ME8\$R%090Z23B"^L-$93S)MW@D41_'X"+J>``0QF&A\:1!-8)U]N`6?G8P4V | |
M,V(2@>]DP9>YFF=S!^5".9F(%`IOP41JLK/MN!N,64!A1!`E,K#8QD=W`J@P | |
MS,I5P"C`(>"AW`#G6?YE=1')($+R$3;X5;;8.0T5=2OB^9#]4188*J$34T,! | |
M8Q,.'4AC'\D\S(4U%K13D8A4!A:"9A9J:N&G;`>?L,8B%`H"TERV1GD^(,AW | |
M+MI`9(5L"X8E0U36"V-G66QD["?3#(UKV5`^R=0Q&G%OBF"4,08FKN(.#'RN | |
M%FL06[BSS570("ZXT;#N&I4!)7O#,7H4U09YD4A6WZVEO&&CB6,`8TY9:3(N | |
M([K!4*;8Y0#OYE"Y7'5&L:%`OF[BKE<;ZH&)53:-RL>]T<!#Q02<U@8=[J%* | |
M@T@`3K.)6B!?92FO=2$<CHL_,S_FS&TZ7V>FO"ZMDQ+('&/AN'7<_\-2,TQ' | |
MF!<(<X.#ZBX2$(4\W7!ZT%*(^Z'K>X9%8VFO)LM2_S-#^@T?+E1ZRU%;2_B* | |
ML:/L_>+)KNMUBJ)82!/E3<;>W8E4V]L.=UHQAO,2;%I7/ZXTG-B6Q!4#7F]N | |
M+9HIKF$.OB&TSXU(#WE]09CM]I7T+)&LU79PIGU`ZT9Q9[&ILR-NX6X]^`4\ | |
MEG$SU5<2>FX4!6HNA:LZ2Z2AAE>V9A/L8)H].+,:*Q_:FSE'C]E+H6T^E]Q4 | |
MQ+Z!Y*(54Z$1<BP(EY=$F5*LD!3PV^2J6Y@&H#55+#'"W:KAAH(*[3@(96H> | |
M[!T--<.,&FR[S:TE:.;%Q[-'I+X%'RV$;O,J"=2\]_T/H+7%3^6+Y<;-K4Z# | |
MRWZ_!-FKE1\0O";=[3>LQM(LK=@1>9R%X<,9-FREI(;!7,[RXKT[MINVY#V0 | |
MEX\6=<!K;=BB%$Y+Z,O)>1K&_:@;E3)[L9DWO'GY\YMW[_9+7A3TN3..I^P. | |
ME3[-9AE<KK`I&#?:=`-<%I++&IW`1[NI`!EKMY_']I9]U$]`U><U;KHPW#1^ | |
M-2S7;,^U;`HL!VYIR/LBH1L!7$_L_QE">BSSJ2CF$.T'XNCB,HK4(B^3%?=H | |
MC-MX!Q=QVM#Z;?5:8.)U@C4W][Y0XD=8TLD+6F\HJKZZKQ6@K,`'%D`UGFP+ | |
M"U57&K>V2B![J:*'&97%+-(N\N+_3'BS.M1QM='65Y5&HX'^X=E5!ME\L>3W | |
*OP%-YHH+BQ0````` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment