[SS] 14Mar2004: eDonkey is the name of a file sharing network, actually it's also the non formal name of the protocol is uses. The eDonkey protocol is a binary protocol that works over TCP, usually port 4662. It also uses UDP in other ports for non-vital stuff. I wrote the following code as an exercise when I was learning Tcl (well, I'm still learning it, as all the simple things that can be combined in may ways it's infinite). It's not a complete implementation, but it's able to connect to another client, ask it for some info like username, server/port used, ID, and try to get the list of shared files (if the client is configured to allow it). The usage is trivial. The program takes two arguments, one is the target host, and the second the target port (4662 should work). You can use it to make sure the file listing feature of your client is not turned on, or as a proof-of-concept of the fact that even with dynamic IP address is possible to identify people on internet using fixed information the software the user is running will report for free. Btw, that's the code: #!/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" # Some initial part of the client-side Emule protocol # implementation. # # Copyright (C) 2003/2004 Salvatore Sanfilippo # Under the same license as Tcl/Tk 8.4 # # This code is already usable to connect to another client IP/Port # (port is usually 4662) and show it's username, server, ID, # and if available the list of shared files. # # Note that I'll never finish this code, this was written when # I was learning some initial Tcl and liked to play with # binary stuff. proc write {fd data} { puts -nonewline $fd $data } proc protostr proto { switch $proto { e3 {format eDonkey} c5 {format {eMule extensions}} d4 {format {eMule compressed}} default {format "Unknown ($proto)"} } } proc cmdstr cmd { switch $cmd { 4b {format {View files answer}} 4c {format {Hello answer}} 4e {format {Message}} 58 {format {File name request}} default {format "Unknown (0x$cmd)"} } } proc mtagstr mtag { switch $mtag { 0 {format Undefined} 1 {format Hash} 2 {format String} 3 {format DWord} 4 {format Float} 5 {format Bool} 6 {format {Bool array}} 7 {format Blob} default {format "Unknown ($mtag)"} } } proc stagstr stag { switch $stag { 1 {format Name} 2 {format {Size of file}} 3 {format Type} 4 {format Format} 5 {format Collection} 6 {format {Part Path}} 7 {format {Part Hash}} 8 {format Copied} 9 {format {Gap start}} 10 {format {Gap end}} 11 {format Description} 12 {format Ping} 13 {format Fail} 14 {format Preference} 15 {format Port} 16 {format Ip} 17 {format Version} 18 {format TempFile} 19 {format Priority} 20 {format Status} 21 {format Availability} 22 {format QTime} 23 {format Parts} default {format "Unknown $stag"} } } # Start if {$argc != 1 && $argc != 2} { puts stderr {Usage: edinfo [port]} exit 1 } if {$argc == 1} {lappend argv 4662} foreach {targethost targetport} $argv break proc readPacket {fd protovar lenvar pktvar} { upvar $protovar proto $lenvar len $pktvar pkt # Read the header set hdr [read $fd 5] puts "Header length: [string length $hdr]" binary scan $hdr H2i proto len puts "Protocol: $proto ([protostr $proto])" puts "Length : $len bytes" # Read the actual packet set pkt [read $fd $len] } proc buildPacket data { set len [string length $data] append pkt "\xe3"; # protocol (eDonkey) append pkt [binary format i $len] append pkt $data } proc sendHelo fd { puts "> Helo" # Build the Hello request append hello "\x01"; # command (Hello) append hello "\x10"; # user hash size (16 bytes) append hello "\x24\x0f\xf8\x30\xdd\x4b\x4e\x50"; # userhash first 8 bytes append hello "\x56\x91\xac\xeb\xae\x52\x4c\x9e"; # userhash last 8 bytes append hello "\xaa\xbb\x00\x00"; # user id = Our IP for High ID append hello "\x36\x12"; # our ports append hello "\x02\x00\x00\x00"; # tag count (must be <= 7) append hello "\x03\x01\x00\x11\x3c\x00\x00\x00"; # Version tag append hello "\x02\x01\x00\x01\x07\x00panzutu"; # Name tag append hello "\x42\x6F\x2B\x50"; # server IP (0 = none) append hello "\x92\x10"; # server port (0 = none) # Send the Hello request set hellopkt [buildPacket $hello] write $fd $hellopkt # Read the packet readPacket $fd proto len reply # Porcess the reply binary scan $reply "cH32H2H2H2H2sia*" cmd userhash x1 x2 x3 x4 port tagcount reply set userid [expr 0x$x4$x3$x2$x1] set ip [expr 0x$x1].[expr 0x$x2].[expr 0x$x3].[expr 0x$x4] if {$userid <= 0xFFFFFF} {set ip "Low ID"} puts "Command : [format %02x $cmd] ([cmdstr [format %02x $cmd]])" puts "UserHash: $userhash" puts "UserId : $userid ($ip)" puts "Port : $port" puts "Tags : $tagcount" # Read the tags while {[incr tagcount -1] >= 0} { binary scan $reply "csa*" mtag taglen reply if {$taglen == 1} { binary scan $reply "ca*" stag reply set tagname [stagstr $stag] } else { binary scan $reply [format "%s%s" a$taglen a*] tagname reply } puts -nonewline " [mtagstr $mtag] $taglen $tagname: " switch $mtag { 2 { binary scan $reply "sa*" strlen reply append fmt "a$strlen" "a*" binary scan $reply $fmt str reply puts "$str ($strlen bytes)" } 3 { binary scan $reply "H2H2H2H2a*" x1 x2 x3 x4 reply set dw [expr 0x$x4$x3$x2$x1] puts $dw } default { puts "Unable to handle this TAG" exit 1 } } } # Read Server and Port binary scan $reply "H2H2H2H2sa*" x1 x2 x3 x4 servport reply set ip [expr 0x$x1].[expr 0x$x2].[expr 0x$x3].[expr 0x$x4] puts "Server IP: $ip" puts "Serv Port: $servport" if {[string length $reply]} { puts -nonewline "WARNING: Spurious data at end of reply:" binary scan $reply H* spurious puts " \[$spurious\]" } } proc hexdump data { set bytesperline 16 set idx 0 set l [string length $data] while {$l} { if {$l < $bytesperline} { set c $l } else { set c $bytesperline } set hexrepr {} set asciirepr {} for {set i 0} {$i < $c} {incr i} { binary scan $data "aa*" byte data binary scan $byte "H2" hexbyte append hexrepr "$hexbyte " if {[string is print $byte]} { append asciirepr $byte } else { append asciirepr . } } puts [format "%08d: %-50.50s|%-18.18s|" $idx $hexrepr $asciirepr] incr l -$c incr idx $c } } proc showGenericReply fd { readPacket $fd proto len reply binary scan $reply "ca*" cmd reply puts "Command : [format %02x $cmd] ([cmdstr [format %02x $cmd]])" puts "Data dump follows:" hexdump $reply } proc sendViewFiles fd { puts "> View Files" # Build the View Files request append pkt "\x4a"; # command (View Files) set hpkt [buildPacket $pkt] write $fd $hpkt # Read the packet showGenericReply $fd } proc sendMessage {fd msg} { puts "> Message \"$msg\"" append pkt "\x4e" [binary format "s" [string length $msg]] $msg set hpkt [buildPacket $pkt] write $fd $hpkt # Read the packet # showGenericReply $fd } proc sendFileStatusRequest {fd hash} { puts "> File Status Request" # Build the File Status Request append pkt "\x4f"; # command (File Request) append pkt $hash; # file hash set hpkt [buildPacket $pkt] write $fd $hpkt # Read the packet readPacket $fd proto len reply puts "File Satatus reply length $len" } proc sendFileNameRequest {fd hash} { puts "> File Name Request" # Build the Files Request request append pkt "\x58"; # command (File Request) append pkt $hash; # file hash # black magic string append pkt "\x4b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04" # Send the request set hpkt [buildPacket $pkt] write $fd $hpkt # Read the packet readPacket $fd proto len reply puts "File Name Request reply length $len" } set fd [socket $targethost $targetport] fconfigure $fd -encoding binary -buffering none sendHelo $fd #sendMessage $fd Hello sendViewFiles $fd #sendFileStatusRequest $fd 0123456789012345 close $fd # vim: filetype=tcl softtabstop=4 shiftwidth=4 ---- [Category Internet]