I'm struggling to reverse engineer a section of data associated with a CRC-16 checksum.
I know the polynom used to calculate the original checksums is 0x8408 but nothing else, I don't know initial value (if any), final XOR value (if any), if the input or the result is reflected...
It seems like there is a known CRC-16 generator using thing polynom, CRC-16-CCITT but despite everything I've tried I just can't understand how the original checksum is being calculated.
Here is the data I've got with their respective checksums. I also included a byte that is between the data and the checksum, it's incremental and I'm not whether it's calculated or not. (see the last two lines, data is almost the same, increment is not the same and yet the checksum are identical)
| DATA |Inc|CRC|
|----------------------------------------------------------|---|---|
00 00 00 00 00 00 01 ef f7 fe ef ff fd ef fb fa fd a2 aa 21 01 f4 e0
00 00 00 00 00 00 01 ef f7 fd ef ff fd fe fb fa fd a2 aa 21 02 f4 d1
00 00 00 00 00 00 01 f7 fe fd fd ff fd df ff fb fd a2 aa 21 03 f4 cd
00 00 00 00 00 00 01 f7 fe fe fd ff f7 ef ff fa fd a2 aa 21 04 f4 c2
00 00 00 00 00 00 01 ef f7 fe ef ff fe ef fb fa fd a2 aa 21 05 f4 db
00 00 00 00 00 00 01 ef f7 fe ef ff fd ef fb fa fd a2 aa 21 06 f4 db
The last byte of each line appears to be 0xF3 + the negative sum of all but the last byte (including the 0xF4). This code works for the 5 examples:
typedef unsigned char uint8_t;
static uint8_t data0[] =
{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xef,0xf7,0xfe,0xef,
0xff,0xfd,0xef,0xfb,0xfa,0xfd,0xa2,0xaa,0x21,0x01,0xf4,0xe0};
static uint8_t data1[] =
{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xef,0xf7,0xfd,0xef,
0xff,0xfd,0xfe,0xfb,0xfa,0xfd,0xa2,0xaa,0x21,0x02,0xf4,0xd1};
static uint8_t data2[] =
{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xf7,0xfe,0xfd,0xfd,
0xff,0xfd,0xdf,0xff,0xfb,0xfd,0xa2,0xaa,0x21,0x03,0xf4,0xcd};
static uint8_t data3[] =
{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xf7,0xfe,0xfe,0xfd,
0xff,0xf7,0xef,0xff,0xfa,0xfd,0xa2,0xaa,0x21,0x04,0xf4,0xc2};
static uint8_t data4[] =
{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xef,0xf7,0xfe,0xef,0xff,
0xfe,0xef,0xfb,0xfa,0xfd,0xa2,0xaa,0x21,0x05,0xf4,0xdb};
static uint8_t data5[] =
{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xef,0xf7,0xfe,0xef,0xff,
0xfd,0xef,0xfb,0xfa,0xfd,0xa2,0xaa,0x21,0x06,0xf4,0xdb};
int main()
{
size_t i;
uint8_t c = 0xf3;
uint8_t s;
s = c;
for(i = 0; i < sizeof(data0)-1; i++)
s -= data0[i];
if (data0[i] != s)
printf("mismatch\n");
s = c;
for (i = 0; i < sizeof(data1) - 1; i++)
s -= data1[i];
if (data1[i] != s)
printf("mismatch\n");
s = c;
for (i = 0; i < sizeof(data2) - 1; i++)
s -= data2[i];
if (data2[i] != s)
printf("mismatch\n");
s = c;
for (i = 0; i < sizeof(data3) - 1; i++)
s -= data3[i];
if (data3[i] != s)
printf("mismatch\n");
s = c;
for (i = 0; i < sizeof(data2) - 1; i++)
s -= data4[i];
if (data4[i] != s)
printf("mismatch\n");
return 0;
}
I'm trying to connect to the Safecom TA-810 (badge/registration system) to automate the process of calculating how long employee's have worked each day. Currently this is done by:
Pulling the data into the official application
Printing a list of all 'registrations'
Manually entering the values from the printed lists into our HR application
This is a job that can take multiple hours which we'd like to see automated. So far the official tech support has been disappointing and refused to share any details.
Using wireshark I have been capturing the UDP transmissions and have pretty much succeeded in understanding how the protocol is built up. I'm only having issues with what i suppose is a CRC field. I don't know how it is calculated (CRC type and parameters) and using which fields ...
This is how a message header looks like:
D0 07 71 BC BE 3B 00 00
D0 07 - Message type
71 BC - This i believe is the CRC
BE 3B - Some kind of session identifier. Stays the same for every message after the initial message (initial message has '00 00' as value)
00 00 - Message number. '01 00', '02 00', '03 00'
Some examples:
Header only examples
E8 03 17 FC 00 00 00 00 -> initial request (#0, no session nr)
D0 07 71 BC BE 3B 00 00 -> Initial response (#0, device sends a session nr)
4C 04 EF BF BE 3B 06 00 -> Message #6, still using the same session # as the initial response
Larger example, which has data
0B 00 07 E1 BE 3B 01 00 7E 45 78 74 65 6E 64 46 6D 74
I've also been trying to figure this out by reading the disassembled code from the original application. The screenshot below happens before the socket.sendto and seems to be related.
Any help will be extremely appreciated.
EDIT: Made some success with debugging the application using ollydbg. The CRC appears in register (reversed) EDX at the selected line in the following screenshot.
Take a look at CRC RevEng. If you can correctly identify the data that the CRC is operating on and the location of the CRC, you should be able to determine the CRC parameters. If it is a CRC.
I've managed to create a php script that does the CRC calculation by debugging the application using OllyDbg.
The CRC is calculated by Adding up every 2 bytes (every short). if the result is larger than a short, the 'most significant short' is added to the 'least significant short' until the result fits in a short. Finally, the CRC (short) is inverted.
I'll add my php script for completeness:
<?php
function CompareHash($telegram)
{
$telegram = str_replace(" ", "", $telegram);
$telegram_crc = substr($telegram, 4, 4);
$telegram = str_replace($telegram_crc, "0000", $telegram);
echo "Telegram: ", $telegram, ', Crc: ', $telegram_crc, ' (', hexdec($telegram_crc), ')<br />';
$crc = 0;
$i = 0;
while ($i < strlen($telegram))
{
$short = substr($telegram, $i, 4);
if (strlen($short) < 4) $short = $short . '00';
$crc += hexdec($short);
$i += 4;
}
echo "Crc: ", $crc, ', inverse: ', ~$crc;
// Region "truncate CRC to Int16"
while($crc > hexdec('FFFF'))
{
$short = $crc & hexdec ('FFFF');
// Region "unsigned shift right by 16 bits"
$crc = $crc >> 16;
$crc = $crc & hexdec ('FFFF');
// End region
$crc = $short + $crc;
}
// End region
// Region "invert Int16"
$crc = ~$crc;
$crc = $crc & hexdec ('FFFF');
// End region
echo ', shifted ', $crc;
if (hexdec($telegram_crc) == $crc)
{
echo "<br />MATCH!!! <br />";
}
else
{
echo "<br />failed .... <br />";
}
}
$s1_full = "E8 03 17 FC 00 00 00 00";
$s2_full = "D0 07 71 BC BE 3B 00 00";
$s3_full = "D0 07 4E D4 E1 23 00 00";
$s4_full = "D0 07 35 32 BE 3B 07 00 7E 44 65 76 69 63 65 4E 61 6D 65 3D 54 41 38 31 30 00";
$s5_full = "0B 00 39 6C BE 3B 05 00 7E 52 46 43 61 72 64 4F 6E";
CompareHash($s1_full);
CompareHash($s2_full);
CompareHash($s3_full);
CompareHash($s4_full);
CompareHash($s5_full);
?>
Thanks for the feedback!
I really can't deal with this piece of code ...
I need help ... I searched on the forum but no topic about return 1 row < multi row
Here it is in a for loop:
for (global.id_increment = 0; global.id_increment < global.max_increment; global.id_increment++)
{
q = GMSQL_QueryExecute(db,
"INSERT INTO Users (id, name, password, age)
SELECT " + string(global.id_increment) + ",'User', 'Pass', 14
FROM dual
WHERE NOT EXISTS (
SELECT id
FROM Users
WHERE Users.id = " + string(global.id_increment) + "
LIMIT 1
)
");
}
GMSQL_QueryExecute is a DLL for GMS
This script is affected to a sprite (object) for adding row in empty id.row
more explained
ID Users : 01 02 03 04 05 06 07 08 09 (all rows)
01 02 04 05 06 09 (case empty)
03 07 08 (query actual return)
03 (the return searched :
the "first match" enable)
I don't know why LIMIT 1 doesn't work
So I really need help
How to deal with it?
I'm sending a COM_EXECUTE_STMT message and the server always returns an:
Error 1048 - #23000 - Column 'number_tinyint' cannot be null
The query is like this:
insert into numbers (
number_tinyint,
number_smallint,
number_mediumint,
number_int,
number_bigint,
number_decimal,
number_float,
number_double
) values
(
?, 679, 778, 875468, 100007654, 198.657809, 432.8, ?)
And what I send in is:
0: 18 00 00 00 17 01 00 00 . . . . . . . .
1: 00 00 01 00 00 00 00 00 . . . . . . . .
2: 01 01 05 0a 29 5c 8f c2 . . . . ) \ . .
3: f5 b0 58 40 . . X #
And simplified for reading:
18 00 00 - size
00 - sequence
17 - type
01 00 00 00 - statement id
00 - flags
01 00 00 00 - iteration-count
00 00 - null bitmap
01 - new params bound flag
01 - byte type
05 - double type
0a - byte value - 10
29 5c 8f c2 f5 b0 58 40 - double value
The statement parameters are 10 (for the tinyint column) and 98.765 (for the double column). From what I can see the message is encoded correctly but it always fails for some reason (at least from what the documentation says)
Am I missing something in here?
From the documentation to which you've linked:
payload:
[ deletia ]
n NULL-bitmap, length: (num-params+7)/8
Therefore, with two parameters in your case, the NULL-bitmap should have a length of (2+7)/8 = 1 byte, whereas you currently have a 2-byte bitmap.
If I have serialized data like:
> a <- 1:5
> a
[1] 1 2 3 4 5
> b <- serialize(a,NULL)
> b
[1] 58 0a 00 00 00 02 00 02 0f 02 00 02 03 00 00 00 00 0d 00 00 00 05 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05
> b[1]
[1] 58
> b[8]
[1] 02
How can I put that serialized data into a MySQL table? I have other info there also. I read that it can be done as blob, but I don't know how it works. I am using RMySQL. I have tried:
dbGetQuery(con, "INSERT INTO table(",b," info, moreInfo, otherStuff, more, date )")
but it won't work.
If I use
query <- paste ("INSERT INTO table(",b," info, moreInfo, otherStuff, more, date )")
dbGetQuery(con,query)
it still won't work.
try this:
library(RODBC)
dt=data.table(a=sample(10),b=sample(10)*10)
sqlSave(con, dt, tablename='sampletablename') # overwrites existing sampletablename table
sqlSave(con, dt, tablename='sampletablename', append=TRUE) # append instead of overwrite