• Welcome to Valhalla Legends Archive.
 

[PHP] Fixing Flappy Webbot

Started by Smarter, September 26, 2007, 06:50 AM

Previous topic - Next topic

Leaky

what I'm trying to encourage you to do is create your own bot... I would be happy to help you and it's a good opportunity to learn some of the more advanced things of programming (atleast the way i did it.. you learn things that apply to all languages) anyways aim me if your interested in learning more or would like some of the tools i've created for making a php bot

Smarter

I would love to, sadly I don't know enough php for that, I can read/edit PHP, and write simple scripts, that's it, and have no real desire to learn it, as I program in C#, which doubles As ASP.NET, so if I was to make a web based bot, i'd simply make it in ASP.NET, however I haven't began my programming in the web side of C#, so for now i'd just like a simply bot in PHP, that I can run some bots on, and modify for my own personal usage, and fappys is the only open source one I can get my hands on ? Although I would love to learn exactly how it is all done in PHP.
Since '99

BrutalNet.Net

Leaky

o.O last i saw asp it looked more like visual basic than c#..... and asp sucks anyways.. you should learn php

idiat

Isn't the Debug function inside the PBuffer class the "hex dumper" you guys are talking about?

Is there any reason fapiko doesn't use pack/unpack? The PacketBuffer seems incomplete.

I could fix this up a bit if fapiko's okay with that and if no one else has a "framework" which they feel would better suit Smarter's needs and if Smarter hasn't decided to do it on his own. I really don't feel like starting another PHP bot right now (I'm not even properly working on my Python bot), but I'm interested to see what others have come up with.
-idiat. Spell it right. No caps either.
-Mary Naivete, sound advice from a sound woman.

Fapiko

I made that bot ages ago just to prove you could make a bot in PHP that could keep the connection alive for a substantial amount of time and not have the script timeout.  The bot uses both AJAX and live PHP output.  The AJAX kicks in when you type and hit enter which thus sends the text to a script that puts it in a queue to go to bnet.  When you load the webbot view script it creates a socket which connects to the backend script and echo's then flushes text as it comes in.  A more efficient way would be to set the PHP INI setting that turns on flushing after every output, can't think of it off the top of my head, but I didn't know about this setting when I coded the bot.  Also, I think my debugging code should still be built in which creates a hex and string representation of all the packets as they go in and out.  Just uncomment the debugging lines.

Leaky

OH SNAP!! FAPIKO IS ALIVE!!.. i thought he didn't really exist.. you know? like the tooth fairy?


anyways...

fapiko's bot is kinda messy and stuff but

here's a packet buffer that i made based off of someone elses vb / c++ packet buffer if ound on these boards



<?php/* class packet module */error_reporting(E_ALL);class Packet {	Private $buffer = "";	Private $RawData = "";	var $PacketFormat = array("pBnet" => 1, "pBNLS" => 2, "pMCP" => 3, "pNone" => 4, "pMatrix" => 5, "pCLS" => 6);	Private $PacketType = array("pIncoming" => 1, "pOutgoing" => 2, "pNull" => 3);	Private $mode = 3;	var $pType = 1;	var $PacketID = NULL;	var $Position = 0;	var $RaiseOverflowErrors = false;	var $packetLength = 0;		function debugOutput($buffer) {		$i = 0;		$j = 0;		$returnString = "";		for($i = 0; $i < strlen($buffer); $i++) {			if(($i != 0) && ($i % 16 == 0)) {				$returnString = $returnString . "\t";				for($j = $i - 16; $j < $i; $j++) {					if(ord($buffer[$j]) < 0x20 || ord($buffer[$j]) > 0x7F)						$returnString = $returnString . '.';					else						$returnString = $returnString . $buffer[$j];				}				// Add a linefeed after the string				$returnString = $returnString . "\n";			}			$returnString = $returnString . bin2hex($buffer[$i]) . " ";		}		if($i != 0 && $i % 16 != 0) {			for($j = 0; $j < ((16 - ($i % 16)) * 3); $j++) {				$returnString = $returnString . " ";			}		}		$returnString = $returnString . "\t";		if($i > 0 && ($i % 16) == 0) {			$j = $i - 16;		}		else {			$j = ($i - ($i % 16));		}		for(; $i >= 0 && $j < $i; $j++) {			if(ord($buffer[$j]) < 0x20 || ord($buffer[$j]) > 0x7F) {				$returnString = $returnString . ".";			}			else {				$returnString = $returnString . $buffer[$j];			}		}		$returnString = $returnString . "\n";		$returnString = $returnString . "Length: " . strlen($buffer) . "\n";		return $returnString;	}		function Packet($type = 1) {		$this->pType = $type;	}		function Reset() {		$this->mode = NULL;		$this->RawData = "";		$this->Position = 0;	}		function SetData($data, $process = false) {		$log = fopen("log.txt", "a");		//echo $this->debugOutput($data) . "\n\n";		flush();		if(is_string($data)) {			$this->RawData = $data;			$this->mode = $this->PacketType["pIncoming"];			if($process) {				if($this->pType == $this->PacketFormat["pBnet"]) {					//printf("[BNET] -> [BOT]\n%s\n\n", $this->debugOutput($data));					fprintf($log, "[BNET] -> [BOT]\n%s\n\n", $this->debugOutput($data));					$this->GetBYTE();					$this->PacketID = $this->GetBYTE();					$this->packetLength = $this->GetWORD();				}				elseif(($this->pType == $this->PacketFormat["pBNLS"]) || ($this->PType == $this->PacketFormat["pMCP"])) {					//printf("[BNLS] -> [BOT]\n%s\n\n", $this->debugOutput($data));					fprintf($log, "[BNLS] -> [BOT]\n%s\n\n", $this->debugOutput($data));					$this->GetWORD();					$this->PacketID = $this->GetBYTE();				}				elseif($this->pType == $this->PacketFormat["pMatrix"]) {					$this->PacketID = $this->GetBYTE();					$this->GetBYTE();				}			}		}		$this->mode = $this->PacketType["pIncoming"];		fclose($log);	}		function getData() {		$tmp = $this->RawData;		$this->Reset();		return $tmp;	}		function Skip($bytes) {		if(is_float($bytes) || is_int($bytes)) {			$this->Position = $this->Position + $bytes;		}	}		function GetString() {		$NTPos = $strTemp = NULL;		$NTPos = strpos($this->RawData, "\x0", $this->Position);		if($NTPos === FALSE) {			if($this->RaiseOverflowErrors) {				trigger_error("Trying to read past end of packet.", E_WARNING);			}			return;		}		$strTemp = substr($this->RawData, $this->Position, $NTPos - $this->Position);		$this->Position = $NTPos+1;		return $strTemp;	}		function GetStringList() {		$strTemp = NULL;		$strTemp = explode("\x0", substr($this->RawData, $this->Position, strpos($this->RawData, "\x0\x0", $this->Position) - $this->Position));		return $strTemp;	}		function GetFixedString($length) {		$rVal = NULL;		if(is_int($length) || is_float($length)) {			if($this->LenData() - $this->Position + 1 >= $length) {				$rVal = substr($this->RawData, $this->Position, $length);				$this->Position = $this->Position + $length;				return $rVal;			}			else {				if($this->RaiseOverflowErrors) {					trigger_error("Trying to read past end of packet.", E_WARNING);				}				return;			}		}	}		function GetBoolean($bytes = 4) {		$rVal = NULL;		if($this->LenData() - $this->Position + 1 >= $bytes) {			$rVal = (int)intval(substr($this->RawData, $this->Position, $bytes));			$this->Position = $this->Position + $bytes;		}		else {			if($this->RaiseOverflowErrors) {				trigger_error("Trying to read past end of packet.", E_WARNING);			}			return;		}		if($rVal == 0) {			return false;		}		else {			return true;		}	}		function DWORD($data, $start = 0) {		$a = $b = $c = $d = NULL;		/*		$a = strrev(str_pad(dechex((substr($data, $start, 1))), 2, '0', STR_PAD_LEFT));		$b = strrev(str_pad(dechex((substr($data, $start + 1, 1))), 2, '0', STR_PAD_LEFT));		$c = strrev(str_pad(dechex((substr($data, $start + 2, 1))), 2, '0', STR_PAD_LEFT));		$d = strrev(str_pad(dechex((substr($data, $start + 3, 1))), 2, '0', STR_PAD_LEFT));		return hexdec(strrev($a . $b . $c . $d));		*/		$data = substr($data, $start, 4);		$a = (((int)$data & 0x000000FF) >> 0);		$b = (((int)$data & 0x0000FF00) >> 8);		$c = (((int)$data & 0x00FF0000) >> 16);		$d = (((int)$data & 0xFF000000) >> 24);		return chr($a) . chr($b) . chr($c) . chr($d);		/*$dcom = new COM("CopyMemoryCom.CopyMemory");		$ret = $dcom->makeDWORD(substr($data, $start, 4));		return $ret;		*/	}		function DWORD2($data, $start = 0) {		$a = $b = $c = $d = NULL;		$a = strrev(str_pad(dechex(ord(substr($data, $start, 1))), 2, '0', STR_PAD_LEFT));		$b = strrev(str_pad(dechex(ord(substr($data, $start + 1, 1))), 2, '0', STR_PAD_LEFT));		$c = strrev(str_pad(dechex(ord(substr($data, $start + 2, 1))), 2, '0', STR_PAD_LEFT));		$d = strrev(str_pad(dechex(ord(substr($data, $start + 3, 1))), 2, '0', STR_PAD_LEFT));		return hexdec(strrev($a . $b . $c . $d));	}		function GetDWORD() {		$rVal = NULL;		if($this->LenData() - $this->Position + 3 >= 4) {			$rVal = $this->DWORD2($this->RawData, $this->Position);			$this->Position = $this->Position + 4;			return $rVal;		}		else {			if($this->RaiseOverflowErrors) {				trigger_error("Trying to read past end of packet.", E_WARNING);			}			return;		}	}		/**	 * Add an array of DWORD's to the packet buffer	 *	 * @param int $length	 * @return array	 */	function GetDWORDArray($length) {		$oS = array();		$i = NULL;		if($length > 0 && (is_float($length) || is_int($length))) {			for($i = 0; $i <= $length - 1; $i++) {				$oS[$i] = $this->GetDWORD();			}			return $oS;		}	}		function WORD($data, $start = 0) {		$a = $b = NULL;		/*		$a = strrev(str_pad(dechex(ord(substr($data, $start, 1))), 2, '0', STR_PAD_LEFT));		$b = strrev(str_pad(dechex(ord(substr($data, $start + 1, 1))) , 2, '0', STR_PAD_LEFT));		return hexdec(strrev($a . $b));		*/		$len = 2;		if(strlen($data) == 3 && intval($data) > 99) {			$len = 3;		}		$data = substr($data, $start, $len);		$a = (((int)$data & 0x00FF) >> 0);		$b = (((int)$data & 0xFF00) >> 8);		return chr($a) . chr($b);	}		function WORD2($data, $start = 0) {		$a = $b = NULL;		$a = strrev(str_pad(dechex(ord(substr($data, $start, 1))), 2, '0', STR_PAD_LEFT));		$b = strrev(str_pad(dechex(ord(substr($data, $start + 1, 1))) , 2, '0', STR_PAD_LEFT));		return hexdec(strrev($a . $b));	}	function GetWORD() {		$rVal = $a = $b = NULL;		if($this->LenData() - $this->Position + 1 >= 4) {			$rVal = $this->WORD2($this->RawData, $this->Position);			$this->Position = $this->Position + 2;			return $rVal;		}		else {			if($this->RaiseOverflowErrors) {				trigger_error("Trying to read past end of packet.", E_WARNING);			}			return;		}	}		function GetWORDArray($length) {		$oS = array();		$i = NULL;		if($length > 0 && (is_float($length) || is_int($length))) {			for($i = 0; $i <= $length - 1; $i++) {				$oS[$i] = $this->GetWORD();			}			return $oS;		}	}		function GetBYTE() {		$return = NULL;		if($this->LenData() - $this->Position >= 1) {			//$return = (int)substr($this->RawData, $this->Position, 1);			$return = ord(substr($this->RawData, $this->Position, 1));			$this->Position = $this->Position + 1;			return $return;		}		else {			if($this->RaiseOverflowErrors) {				trigger_error("Trying to read past end of packet.", E_WARNING);			}		}	}		function GetStringArray($length) {		$oS = array();		$i = NULL;		if($length > 0 && (is_float($length) || is_int($length))) {			for($i = 0; $i <= $length - 1; $i++) {				$oS[$i] = GetString();			}			return $oS;		}	}		function LenData() {		return strlen($this->RawData);	}		function buildUDPHeader($header = array()) {		switch($header["class"]) {			case 0:				$this->RawData = $this->WORD($header["sent"]) . $this->WORD($header["recv"]) . "\x0" . $this->BYTE($header['packetid']) . $this->BYTE($header['playerid']) . $this->BYTE($header['resend']) . $this->RawData;				$this->RawData = $this->WORD(strlen($this->RawData) + 4) . $this->RawData;				$this->RawData = ($this->DWORD(0x00) . $this->UDPCheckSum($this->WORD(0x00) . $this->RawData) . $this->RawData);			break;					}	}		function Send(&$socket, $PacketID = NULL, $Format = 1, $host = "", $port = 6112) {		$log = fopen("log.txt", "a");		switch($Format) {			case $this->PacketFormat["pBnet"]:				//printf("[BOT] -> [BNET]\n%s\n\n", $this->debugOutput(chr(0xFF) . chr($PacketID) . $this->WORD(strlen($this->RawData) + 4) . $this->RawData));				fprintf($log, "[BOT] -> [BNET]\n%s\n\n", $this->debugOutput(chr(0xFF) . chr($PacketID) . $this->WORD(strlen($this->RawData) + 4) . $this->RawData));				$socket->sendData(chr(0xFF) . chr($PacketID) . $this->WORD(strlen($this->RawData) + 4) . $this->RawData);			break;			case $this->PacketFormat["pBNLS"]:			case $this->PacketFormat["pMCP"]:				//printf("[BOT] -> [BNLS]\n%s\n\n", $this->debugOutput($this->WORD(strlen($this->RawData) + 3) . chr($PacketID) . $this->RawData));				fprintf($log, "[BOT] -> [BNLS]\n%s\n\n", $this->debugOutput($this->WORD(strlen($this->RawData) + 3) . chr($PacketID) . $this->RawData));				$socket->sendData($this->WORD(strlen($this->RawData) + 3) . chr($PacketID) . $this->RawData);			break;			case $this->PacketFormat["pMatrix"]:				$socket->sendData($this->BYTE($PacketID) . chr(strlen($this->RawData) + 3) . $this->RawData);			break;			case $this->PacketFormat["pCLS"]:				printf("[BOT] -> [%s:%d]\n%s\n\n", $host, $port, $this->debugOutput($this->RawData));				fprintf($log, "[BOT] -> [%s:%d]\n%s\n\n", $host, $port, $this->debugOutput($this->RawData));				socket_sendto($socket, $this->RawData, strlen($this->RawData), 0, $host, $port);			break;			default:				fprintf($log, "[BOT] -> [BNET]\n%s\n\n", $this->debugOutput($this->RawData));				$socket->sendData($this->RawData);		}		$this->Reset();	}		function InsertString($Data) {		if($this->mode == $this->PacketType["pIncoming"]) {			return;		}		$this->mode = $this->PacketType["pOutgoing"];		$this->RawData = $this->RawData . $Data . chr(0);	}		function InsertStringList($Data) {		if($this->mode == $this->PacketType["pIncoming"]) {			return;		}		$this->mode = $this->PacketType["pOutgoing"];		$i = NULL;		if(is_array($Data)) {			for($i = 0; $i < count($Data); $i++) {				$this->RawData = $this->RawData . $Data[$i] . chr(0);			}			$this->RawData = $this->RawData . chr(0);		}	}		function InsertStringArray($Data) {		if($this->mode == $this->PacketType["pIncoming"]) {			return;		}		$this->mode = $this->PacketType["pOutgoing"];		$i = NULL;		if(is_array($Data)) {			for($i = 0; $i < count($Data); $i++) {				$this->RawData = $this->RawData . $Data[$i] . chr(0);			}		}	}		function InsertNTString($Data) {		$this->InsertString($Data);	}		function InsertNonNTString($Data) {		if($this->mode == $this->PacketType["pIncoming"]) {			return;		}		$this->mode = $this->PacketType["pOutgoing"];		$this->RawData = $this->RawData . $Data;	}		function InsertByte($Data) {		if($this->mode == $this->PacketType["pIncoming"]) {			return;		}		$this->mode = $this->PacketType["pOutgoing"];		$this->RawData = $this->RawData . $this->BYTE($Data);	}		function InsertWORD($data) {		if($this->mode == $this->PacketType["pIncoming"]) {			return;		}		$this->mode = $this->PacketType["pOutgoing"];		$this->RawData = $this->RawData . $this->WORD($data);	}		/**	 * Add a DWORD to the packet buffer	 *	 * @param string $data	 */	function InsertDWORD($data) {		if($this->mode == $this->PacketType["pIncoming"]) {			return;		}		$this->mode = $this->PacketType["pOutgoing"];		$this->RawData = $this->RawData . $this->DWORD($data);	}		/**	 * Add an array of DWORD's to the packet buffer	 *	 * @param array $data	 */	function InsertDWORDArray($data) {		if($this->mode == $this->PacketType["pIncoming"]) {			return;		}		$this->mode = $this->PacketType["pOutgoing"];		$i = NULL;		if(is_array($data)) {			for($i = 0; $i < count($data); $i++) {				$this->RawData = $this->RawData . $this->DWORD($data[$i]);			}		}	}		function BYTE($data) {		//return (int)substr($data, 0, 1);		return chr($data);	}	/*	function SubSum() {		$length = strlen($this->DWORD(0x00) . $this->RawData) - 2;		$tmpData = $this->DWORD(0x00) . $this->RawData;		$sum1 = $sum2 = 0;		for($iY = 0; $iY <= $length - 1; $iY++) {			printf("L %d\n", $sum2);			$i = $length - $iY;			$sum2 = $sum2 + ord(substr($tmpData, $i, 1));			if( $sum2 > 0xFF ) {				$sum2 = $sum2 - 0xFF;			}			$sum1 = $sum1 + $sum2;		}		return (($sum2 & 0xFF)<<8) | (($sum1 % 0xFF) & 0xFF);	}		function UDPChecksum() {		$subsum = $this->SubSum();		printf("subsum\n%s\n", $this->debugOutput($subsum));		$a = 0xFF - (($subsum AND 0xFF) + ($subsum >> 8)) % 0xFF;		$b = (int)(((0xFF - ($a + ($subsum << 8)) % 0xFF) AND 0xFF) OR ($a >> 8));		printf("%s\n\n", $this->debugOutput($b));		$ret = $this->WORD($b);		return $ret;	}*/	function SubCheckSum($buff, $length) {		$sum1 = $sum2 = "";		$i = $iY = 0;		for($iY = 0; $iY <= $length; $iY++) {			$i = $length - $iY;			$sum2 = $sum2 + ord(substr($buff, $i, 1));			if($sum2 > 0xFF) {				$sum2 = $sum2 - 0xFF;			}			$sum1 = $sum1 + $sum2;		}		return ((($sum2 & 0xFF) << 8) | (($sum1 % 0xFF) & 0XFF));	}		function UDPCheckSum($buff) {		$tmpData = $buff;		$length = $this->WORD2(substr($tmpData, 2, 2)) - 2;		$subsum = $this->SubCheckSum(substr($tmpData, 2), $length);		$a = 0xFF - (($subsum & 0xFF) + ($subsum >> 8)) % 0XFF;		$b = ((((0xFF - ($a + ($subsum >> 8)) % 0xFF) & 0xFF) | ($a << 8)));		eval('$b = "\x' . substr(dechex($b), 2, 2) . '\x' . substr(dechex($b), 0, 2) . '";');		$ret = $b;		return $ret;	}		}?>






it's been modified a bit tho my packet buffer supports sc udp packets (BuildUDPHeader and UDPCheckSum) also



if anyone thinks they can improve upon my packet buffer feel free to

:P i release the packet buffer under the Creative Commons license
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

:P because i like open source and i like forcing people to share

Camel

Quote from: Leaky on September 26, 2007, 03:31 PM
I could never figure pack out so i did it a different way...

Pack is pretty cryptic, but it's probably the best option.

Leaky

can pack make DWORD and WORD's? o.O if it can :P would you be so kind as to example?

idiat

#23
I can't find the source code to my old PHP bot, but I have a PacketBuffer I wrote in Python which uses pack/unpack:

def InsertWORD(self, txt):
self.Buffer = self.Buffer + struct.pack("<H", txt)

def InsertDWORD(self, txt):
self.Buffer = self.Buffer + struct.pack("<L", txt)


unpack to extract DWORDs, WORDs, bytes, etc:

header = struct.unpack("<2cH", packet)

("packet" has the BNCS packet header only)
header[0] = 0xff
header[1] = ID
header[2] = packet length
-idiat. Spell it right. No caps either.
-Mary Naivete, sound advice from a sound woman.

Leaky

that looks alot simpler and prolly more reliable than my current method..

i'll prolly use pack when i make my bncs server in php

Yegg

idiat: You don't need the '<' in your first argument to pack().

Leaky: Perl's pack function does the same thing as Python's only the arguments are different (same method Ruby uses).

http://www.perl.com/doc/manual/html/pod/perlfunc/pack.html
http://us3.php.net/pack

Since PHP borrows from Perl, I decided to check a manual on both. Both pack functions are the same. Should be easy to figure out from there.

Leaky


Smarter

Quote from: idiat on September 26, 2007, 08:20 PM
Isn't the Debug function inside the PBuffer class the "hex dumper" you guys are talking about?

Is there any reason fapiko doesn't use pack/unpack? The PacketBuffer seems incomplete.

I could fix this up a bit if fapiko's okay with that and if no one else has a "framework" which they feel would better suit Smarter's needs and if Smarter hasn't decided to do it on his own. I really don't feel like starting another PHP bot right now (I'm not even properly working on my Python bot), but I'm interested to see what others have come up with.

Fappys bot is open source just for that exact reason, you can do as you wish to it, if you do modify it, into a better working bot, could you be so kind as to provide me with a copy? :-D
Since '99

BrutalNet.Net