02 - kali's beginning programming guide

Wrote new code? Fixed a bug? Want to discuss technical stuff? Feel free to post it here.

Moderator: Moderators

Message
Author
kali
OpenKore Monk
OpenKore Monk
Posts: 457
Joined: 04 Apr 2008, 10:10

02 - kali's beginning programming guide

#1 Post by kali »

In OpenKore's source code you'll sometimes see packing strings like

Code: Select all

V Z40 a32 v
or

Code: Select all

V Z24 Z24 C
What does this mean?

As a refresher, look up http://www.rubydoc.info/stdlib/core/Array%3Apack

So from that link you'll see that the packing string

Code: Select all

V Z40 a32 v
means:

Code: Select all

V         | Integer | 32-bit unsigned, VAX (little-endian) byte order
a         | String  | same as ``a'', except that null is added with *
Z         | String  | arbitrary binary string (null padded, count is width)
 v         | Integer | 16-bit unsigned, VAX (little-endian) byte order
Now we can recreate our login packet.

Like I mentioned in the previous section as well as the wiki entry on the network subsystem, Ragnarok's packets are heralded by a packet switch (aka message ID). In this particular case we're interested in something called the "master_login" packet, which is "0A76" in phRO and thRO, and "0064" in iRO restart.

Time to do some code to test this out :)

But first, if you're in windows you'll need the Windows Subsystem for Linux https://msdn.microsoft.com/en-us/comman ... tall_guide so you can follow along. Mac users already have ruby installed, and Linux users can just use apt-get to install ruby.

You'll also need to install libmcrypt-dev in linux to make use of the cryptography library.

We're gonna need a few gems (which are libraries; code that has been packaged to be reused by other developers) installed, so type these in:

Code: Select all

gem install ruby-mcrypt
gem install hexdump
Then in a file called ragnarok.rb paste these in:

Code: Select all

require "socket"
require "mcrypt"
require "hexdump"

packet_switch = [0x0a76].pack("v")
version = [0x0018].pack("V")
username = "username".ljust(40, "\0")
password = "password".ljust(16, "\0")
crypt_key = [0x06, 0xA9, 0x21, 0x40, 0x36, 0xB8, 0xA1, 0x5B, 0x51, 0x2E, 0x03, 0xD5, 0x34, 0x12, 0x00, 0x06, 0x06, 0xA9, 0x21, 0x40, 0x36, 0xB8, 0xA1, 0x5B, 0x51, 0x2E, 0x03, 0xD5, 0x34, 0x12, 0x00, 0x06].pack("C32")
cipher = Mcrypt.new(:rijndael_256, :ecb, crypt_key, nil, :zeros)
password_rijndael = cipher.encrypt(password)
master_version = [0x000f].pack("v")

packet = packet_switch + version + username + password_rijndael + master_version
Hexdump.dump(packet) # dumps the packet to the screen

ip_address = "116.93.119.116" # replace with the correct ip address; this one is for phRO
ip_port = 6900 # same here, replace with the correct port
socket = TCPSocket.new ip_address, ip_port
puts "sending"
socket.write(packet)
puts "receiving"
data = socket.recvfrom(1024)
Hexdump.dump(data.pack("A*"))
data = socket.recvfrom(1024)
puts data.pack("H*")
Hexdump.dump(data.pack("A*"))
Then to run the file, type

Code: Select all

ruby ragnarok.rb
Try it out and see that you just communicated with the server. You should see output similar to this:

Code: Select all

 0>   b5 01 fe ff ff ff fe ff ff ff 00 00 00 00 00 00  |................|
 16>  00 00                                            |..|

 0>   76 02 73 00 00 00 00 00    00 00 00 00 00 00 00 00    v.s.............
 16>  00 00 00 00 00 00 00 00    00 00 00 00 00 00 00 00    ........ .......
 32>  00 00 00 00 00 00 00 00    00 00 00 00 00 00 00 64    ...............d
 48>  00 00 00 74 5D 77 1E 94    11 54 68 6F 72 20 28 4E    ...t]w...Thor (N
 64>  65 77 29 00 00 00 00 00    00 00 00 00 00 7B 1A 00    ew)..........{..
 80>  00 00 00 74 5D 78 86 94    11 4C 6F 6B 69 00 00 00    ...t]x...Loki...
 96>  00 00 00 00 00 00 00 00    00 00 00 00 00 25 37 00    .............%7.
112> 00 00 00                                              ...
Here's the quiz: what do these two packets contain? Hint: you can use the OpenKore source code to figure out the packing strings and match the portion to its description.

I understand that this is all so complicated with all the encryption and such, so next time let's try working on a less protected server, like iRO restart.
Got your topic trashed by a mod?

Trashing topics is one click, and moving a topic to its proper forum is a lot harder. You expend the least effort in deciding where to post, mods expend the least effort by trashing.

Have a nice day.

c4c1n6kr3m1
The Way Of Human
The Way Of Human
Posts: 150
Joined: 24 Mar 2012, 04:13
Noob?: Yes

Re: 02 - kali's beginning programming guide

#2 Post by c4c1n6kr3m1 »

Can you give explanation for "x" ?

here's my problem

my char is female but when i type "s" , it is shown "Boy"

the code from serverType0.pm

Code: Select all

my ($cID,$exp,$zeny,$jobExp,$jobLevel, $opt1, $opt2, $option, $stance, $manner, $statpt,
$hp,$maxHp,$sp,$maxSp, $walkspeed, $jobId,$hairstyle, $weapon, $level, $skillpt,$headLow, $shield,$headTop,$headMid,$hairColor,$clothesColor,$name,$str,$agi,$vit,$int,$dex,$luk,$slot, $rename, $unknown, $mapname, $deleteDate) =
			unpack($unpack_string, substr($args->{RAW_MSG}, $i));
and from receive.pm

Code: Select all

return 'a4 V9 v V2 v14 Z24 C8 v Z16 V x4 x4 x4 C' if $_ == 145;
this part of the 099D data , i don't want to list the char id, so i cut the first 368 byte and change name to ABCD

Code: Select all


368>  00 00 00 00 41 42 43 44    00 00 00 00 00 00 00 00    ....ABCD........
384>  00 00 00 00 00 00 00 00    00 00 00 00 01 01 01 01    ................
400>  01 01 02 00 00 00 6E 65    77 5F 31 2D 31 2E 67 61    ......new_1-1.ga
416>  74 00 00 00 00 00 00 00    00 00 00 00 00 00 00 00    t...............
432>  00 00 00 00 00 00 00
$name is Z24 (41 42 43 44 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 )

$str,$agi,$vit,$int,$dex,$luk,$slot, $rename, $unknown, are C8 v ( 01 01 01 01 01 01 02 00 00 00 )

$mapname is Z16 (6E 65 77 5F 31 2D 31 2E 67 61 00 00 00 00 00 00 )

and $deleteDate is V ( 00 00 00 00 )

and the rest "x4 x4 x4 C" ( 00 00 00 00 00 00 00 00 00 00 00 00 00 )

I believe gender is the "last byte" , the last 00 (is it 'C' ?)
so i use this , which works fine now

Code: Select all

$chars[$slot]{sex} = unpack( 'C', substr($args->{RAW_MSG}, $i + $blockSize -1));

but i don't understand the 'x4' , Can you give explanation for "x4"
is "x" works like "a" ?

kali
OpenKore Monk
OpenKore Monk
Posts: 457
Joined: 04 Apr 2008, 10:10

Re: 02 - kali's beginning programming guide

#3 Post by kali »

x means to just read the byte as is, but don't parse it. it is openkore specific, but yes you can treat it as an a
Got your topic trashed by a mod?

Trashing topics is one click, and moving a topic to its proper forum is a lot harder. You expend the least effort in deciding where to post, mods expend the least effort by trashing.

Have a nice day.

kali
OpenKore Monk
OpenKore Monk
Posts: 457
Joined: 04 Apr 2008, 10:10

Re: 02 - kali's beginning programming guide

#4 Post by kali »

great work btw figuring it all out by yourself. would you mind sending a pull request so others can benefit too? :)
Got your topic trashed by a mod?

Trashing topics is one click, and moving a topic to its proper forum is a lot harder. You expend the least effort in deciding where to post, mods expend the least effort by trashing.

Have a nice day.

Post Reply