The sketch below demonstrates how you can use ICSP (In Circuit Serial Programming) to investigate the device signature, and other information, about target chips that you are interested in.
Without needing any extra hardware, or software, apart from the serial monitor, you can find out the device signature, and get a sumcheck of the bootloader.
You can get the code from GitHub:
https://github.com/nickgammon/arduino_sketches
(See the Atmega_Board_Detector folder).

For each chip you need to wire MISO/MOSI/SCK together, and connect D10 on your "main" chip to the reset pin of the device under test. In this case:
For boards which have an ICSP header, it helps to make up a programming cable (although not essential). You can do this by getting a 6-pin IDC cable, and cutting the 5th wire out of circuit and soldering a pin onto it, like this:

This wire (the reset signal) gets plugged into D10 on the Arduino with the detection sketch on it, as in the images below.
If you don't have such a cable, just connect together the pins as described below.
If a bootloader is detected, the entire bootloader is dumped. Also an MD5 sumcheck is taken. This lets you compare sumchecks to a "known" board, and work out whether a board has an Optiboot loader, or other, by making a list of MD5 sums for each bootloader.

(Ruggeduino depicted)
If you don't have the special IDC cable, here is how you can wire up each pin directly:




Hopefully the sketch illustrates how you might write fairly simple code to investigate the contents of another processor, find its signature, and download its flash memory.
I have only tested this sketch with the boards pictured in this post. I can't guarantee that it will work with every board/chip you might have to hand.
I have keyed in the signatures for various other chips from the Atmega datasheets. It should work for those as well. See the "signatures" table in the sketch for supported processors.
Use at your own risk.
Certain combinations of fuse bytes may make the sketch not work. In particular if you have disabled SPI programming.
The thread below describes a sketch you can use to reprogram your bootloader:
http://www.gammon.com.au/forum/?id=11635
As an alternative to a crystal or resonator, the sketch also outputs an 8 MHz clock on pin D9 of the programming board (using Timer 1). Thus you just need to connect D9 on the programming board to XTAL1 of the target board and this will provide a clock signal, enabling this sketch to run.
[EDIT]
Modifications
Version 1.1 released on 5th May 2012. Added support for ATtiny84 family, slowed down SPI clock by a factor of 2 to make it more reliable.
Version 1.9 released on 23 August 2014. Fixed problem where some chips (eg. Atmega168) would report incorrect bootloader information because it was reading the wrong fuse byte.
Without needing any extra hardware, or software, apart from the serial monitor, you can find out the device signature, and get a sumcheck of the bootloader.
Sketch
You can get the code from GitHub:
https://github.com/nickgammon/arduino_sketches
(See the Atmega_Board_Detector folder).
Example output for ATtiny85
Atmega chip detector.
Entered programming mode OK.
Signature = 1E 93 0B
Processor = ATtiny85
Flash memory size = 8192
LFuse = E2
HFuse = DF
EFuse = FF
Lock byte = FF
No bootloader support.
First 256 bytes of program memory:
0: 1B C0 3F C0 3E C0 3A C1 A8 C2 3B C0 3A C0 39 C0
10: 38 C0 37 C0 36 C0 35 C0 4A C0 33 C0 32 C0 00 37
20: 00 38 00 36 01 01 01 01 01 01 01 02 04 08 10 20
30: 01 03 00 00 00 00 69 00 11 24 1F BE CF E5 D2 E0
40: DE BF CD BF 10 E0 A0 E6 B0 E0 E6 E6 F8 E0 02 C0
50: 05 90 0D 92 A2 36 B1 07 D9 F7 10 E0 A2 E6 B0 E0
60: 01 C0 1D 92 AA 38 B1 07 E1 F7 10 E0 C8 E3 D0 E0
70: 03 C0 22 97 FE 01 F1 D3 C6 33 D1 07 D1 F7 91 D3
80: F0 C3 BE CF 96 B1 16 B8 14 BE 88 E1 81 BD 81 E6
90: 81 BD A8 95 85 B7 87 7E 80 61 85 BF 85 B7 80 62
A0: 85 BF 88 95 85 B7 8F 7D 85 BF 96 B9 08 95 1F 92
B0: 0F 92 0F B6 0F 92 11 24 8F 93 88 E1 0F B6 F8 94
C0: 81 BD 11 BC 0F BE 8F 91 0F 90 0F BE 0F 90 1F 90
D0: 18 95 82 E6 90 E0 A9 D1 08 95 1F 93 CF 93 DF 93
E0: 82 E6 90 E0 61 E0 40 E2 52 E0 28 E9 38 E0 DD D1
F0: 80 91 68 00 61 E0 20 D3 C0 E0 D0 E0 82 E6 90 E0
Wiring for ATtiny85

For each chip you need to wire MISO/MOSI/SCK together, and connect D10 on your "main" chip to the reset pin of the device under test. In this case:
Arduino Uno ATtiny
D10 (SS) 1
D11 (MOSI) 5
D12 (MISO) 6
D13 (SCK) 7
Gnd 4
+5V 8
Programming cable
For boards which have an ICSP header, it helps to make up a programming cable (although not essential). You can do this by getting a 6-pin IDC cable, and cutting the 5th wire out of circuit and soldering a pin onto it, like this:

This wire (the reset signal) gets plugged into D10 on the Arduino with the detection sketch on it, as in the images below.
If you don't have such a cable, just connect together the pins as described below.
Example output for Uno
Atmega chip detector.
Entered programming mode OK.
Signature = 1E 95 0F
Processor = ATmega328P
Flash memory size = 32768
LFuse = FF
HFuse = DE
EFuse = FD
Lock byte = CF
Bootloader in use: Yes
EEPROM preserved through erase: No
Watchdog timer always on: No
Bootloader is 512 bytes starting at 7E00
Bootloader:
7E00: 11 24 84 B7 14 BE 81 FF E6 D0 85 E0 80 93 81 00
7E10: 82 E0 80 93 C0 00 88 E1 80 93 C1 00 86 E0 80 93
...
7FE0: E7 DF 80 32 09 F0 F7 DF 84 E1 DA CF 1F 93 18 2F
7FF0: DF DF 11 50 E9 F7 F4 DF 1F 91 08 95 FF FF FF FF
MD5 sum of bootloader = 0F 02 31 72 95 C8 F7 FD 1B B7 07 17 85 A5 66 87
First 256 bytes of program memory:
0: 0C 94 35 00 0C 94 5D 00 0C 94 5D 00 0C 94 5D 00
10: 0C 94 5D 00 0C 94 5D 00 0C 94 5D 00 0C 94 5D 00
20: 0C 94 5D 00 0C 94 5D 00 0C 94 5D 00 0C 94 5D 00
30: 0C 94 5D 00 0C 94 5D 00 0C 94 5D 00 0C 94 5D 00
40: 0C 94 80 03 0C 94 5D 00 0C 94 C9 00 0C 94 5D 00
50: 0C 94 5D 00 0C 94 5D 00 0C 94 5D 00 0C 94 5D 00
60: 0C 94 5D 00 0C 94 5D 00 E5 01 11 24 1F BE CF EF
70: D8 E0 DE BF CD BF 11 E0 A0 E0 B1 E0 E0 E9 F8 E0
80: 02 C0 05 90 0D 92 A2 32 B1 07 D9 F7 11 E0 A2 E2
90: B1 E0 01 C0 1D 92 A2 3C B1 07 E1 F7 10 E0 CA E6
A0: D0 E0 04 C0 22 97 FE 01 0E 94 42 04 C8 36 D1 07
B0: C9 F7 0E 94 1F 02 0C 94 46 04 0C 94 00 00 08 95
C0: FF 92 0F 93 1F 93 06 EA 11 E0 C8 01 40 E0 52 EC
D0: 61 E0 70 E0 0E 94 FA 00 C8 01 0E 94 44 03 C8 01
E0: 60 E0 71 E0 0E 94 75 03 91 E2 F9 2E E0 E0 F0 E0
F0: F0 92 57 00 E4 91 C8 01 6E 2F 40 E1 50 E0 0E 94
If a bootloader is detected, the entire bootloader is dumped. Also an MD5 sumcheck is taken. This lets you compare sumchecks to a "known" board, and work out whether a board has an Optiboot loader, or other, by making a list of MD5 sums for each bootloader.
Wiring for Uno and similar

(Ruggeduino depicted)
Arduino Uno Target Uno
D10 (SS) Reset
D11 (MOSI) D11
D12 (MISO) D12
D13 (SCK) D13
Gnd Gnd
+5V +5V
If you don't have the special IDC cable, here is how you can wire up each pin directly:

Example output for Mega2560
Atmega chip detector.
Entered programming mode OK.
Signature = 1E 98 01
Processor = ATmega2560
Flash memory size = 262144
LFuse = FF
HFuse = D8
EFuse = FD
Lock byte = FF
Bootloader in use: Yes
EEPROM preserved through erase: No
Watchdog timer always on: No
Bootloader is 8192 bytes starting at 3E000
Bootloader:
3E000: 0D 94 89 F1 0D 94 B2 F1 0D 94 B2 F1 0D 94 B2 F1
3E010: 0D 94 B2 F1 0D 94 B2 F1 0D 94 B2 F1 0D 94 B2 F1
...
3FFD0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
3FFE0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
3FFF0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
MD5 sum of bootloader = B9 49 93 09 49 1A 64 6E CD 58 47 89 C2 D8 A4 6C
First 256 bytes of program memory:
0: 0C 94 4C 01 0C 94 79 01 0C 94 79 01 0C 94 79 01
10: 0C 94 79 01 0C 94 79 01 0C 94 79 01 0C 94 79 01
20: 0C 94 79 01 0C 94 21 02 0C 94 4F 02 0C 94 7D 02
30: 0C 94 79 01 0C 94 79 01 0C 94 79 01 0C 94 79 01
40: 0C 94 79 01 0C 94 79 01 0C 94 79 01 0C 94 79 01
50: 0C 94 79 01 0C 94 79 01 0C 94 79 01 0C 94 71 05
60: 0C 94 79 01 0C 94 79 01 0C 94 79 01 0C 94 79 01
70: 0C 94 79 01 0C 94 79 01 0C 94 79 01 0C 94 79 01
80: 0C 94 79 01 0C 94 79 01 0C 94 79 01 0C 94 79 01
90: 0C 94 79 01 0C 94 79 01 0C 94 79 01 0C 94 79 01
A0: 0C 94 79 01 0C 94 79 01 0C 94 79 01 0C 94 79 01
B0: 0C 94 79 01 0C 94 79 01 0C 94 79 01 0C 94 79 01
C0: 0C 94 79 01 0C 94 79 01 0C 94 79 01 0C 94 79 01
D0: 0C 94 79 01 0C 94 79 01 0C 94 79 01 0C 94 79 01
E0: 0C 94 79 01 00 C2 01 00 01 00 11 00 11 00 0C 00
F0: 00 E1 00 00 0A 00 25 00 25 00 21 00 00 96 00 00
Wiring for Mega2560 and similar

Arduino Uno Target Mega2560
D10 (SS) Reset
D11 (MOSI) D51
D12 (MISO) D50
D13 (SCK) D52
Gnd Gnd
+5V +5V
Example output for Sanguino
Atmega chip detector.
Entered programming mode OK.
Signature = 1E 96 0A
Processor = ATmega644P
Flash memory size = 65536
LFuse = FF
HFuse = DC
EFuse = FD
Lock byte = CF
Bootloader in use: Yes
EEPROM preserved through erase: No
Watchdog timer always on: No
Bootloader is 2048 bytes starting at F800
Bootloader:
F800: 0C 94 3E 7C 0C 94 5B 7C 0C 94 5B 7C 0C 94 5B 7C
F810: 0C 94 5B 7C 0C 94 5B 7C 0C 94 5B 7C 0C 94 5B 7C
...
FFE0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FFF0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
MD5 sum of bootloader = 51 69 10 40 8F 07 81 C6 48 51 54 5E 96 73 C2 EB
First 256 bytes of program memory:
0: 0C 94 77 00 0C 94 9F 00 0C 94 9F 00 0C 94 9F 00
10: 0C 94 9F 00 0C 94 9F 00 0C 94 9F 00 0C 94 9F 00
20: 0C 94 9F 00 0C 94 9F 00 0C 94 9F 00 0C 94 9F 00
30: 0C 94 9F 00 0C 94 9F 00 0C 94 9F 00 0C 94 9F 00
40: 0C 94 9F 00 0C 94 9F 00 0C 94 CD 00 0C 94 9F 00
50: 0C 94 0A 02 0C 94 9F 00 0C 94 9F 00 0C 94 9F 00
60: 0C 94 9F 00 0C 94 9F 00 0C 94 9F 00 0C 94 9F 00
70: 0C 94 47 02 0C 94 9F 00 0C 94 9F 00 00 21 24 27
80: 2A 00 22 25 28 2B 00 20 23 26 29 02 02 02 02 02
90: 02 02 02 04 04 04 04 04 04 04 04 03 03 03 03 03
A0: 03 03 03 01 01 01 01 01 01 01 01 01 02 04 08 10
B0: 20 40 80 01 02 04 08 10 20 40 80 01 02 04 08 10
C0: 20 40 80 80 40 20 10 08 04 02 01 00 00 00 01 02
D0: 00 00 00 00 00 00 00 04 03 07 06 00 00 00 00 00
E0: 00 00 00 00 00 00 00 00 00 00 00 00 90 03 11 24
F0: 1F BE CF EF D0 E1 DE BF CD BF 11 E0 A0 E0 B1 E0
Wiring for Sanguino and similar

Arduino Uno Target Sanguino
D10 (SS) Reset (pin 9)
D11 (MOSI) Pin 6
D12 (MISO) Pin 7
D13 (SCK) Pin 8
Gnd Gnd
+5V +5V
Example output for ATtiny84
Atmega chip detector.
Entered programming mode OK.
Signature = 1E 93 0C
Processor = ATtiny84
Flash memory size = 8192
LFuse = 62
HFuse = DF
EFuse = FF
Lock byte = FF
No bootloader support.
First 256 bytes of program memory:
0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
10: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
20: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
30: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
40: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
50: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
60: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
70: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
80: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
90: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
A0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
B0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
C0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
D0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
E0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
F0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
Wiring for ATtiny84 and similar

Arduino Uno ATtiny84
D10 (SS) Reset (pin 4)
D11 (MOSI) Pin 7
D12 (MISO) Pin 8
D13 (SCK) Pin 9
Gnd Gnd
+5V +5V
Hopefully the sketch illustrates how you might write fairly simple code to investigate the contents of another processor, find its signature, and download its flash memory.
Caveats
I have only tested this sketch with the boards pictured in this post. I can't guarantee that it will work with every board/chip you might have to hand.
I have keyed in the signatures for various other chips from the Atmega datasheets. It should work for those as well. See the "signatures" table in the sketch for supported processors.
Use at your own risk.
Certain combinations of fuse bytes may make the sketch not work. In particular if you have disabled SPI programming.
Uploading a new bootloader
The thread below describes a sketch you can use to reprogram your bootloader:
http://www.gammon.com.au/forum/?id=11635
Alternate clock source
As an alternative to a crystal or resonator, the sketch also outputs an 8 MHz clock on pin D9 of the programming board (using Timer 1). Thus you just need to connect D9 on the programming board to XTAL1 of the target board and this will provide a clock signal, enabling this sketch to run.
[EDIT]
Modifications
Version 1.1 released on 5th May 2012. Added support for ATtiny84 family, slowed down SPI clock by a factor of 2 to make it more reliable.
Version 1.9 released on 23 August 2014. Fixed problem where some chips (eg. Atmega168) would report incorrect bootloader information because it was reading the wrong fuse byte.