I´m playing around with two Xbees, one defined as coordinator, another as router. I want to read information about the network interoperably so i decided to use the ZDO messages.
I send a message like this ((profile ID 0x00 00, cluster ID 0x 00 31) and receive for example the following response from the router:
7E 00 2D 91 00 13 A2 00 40 E5 F0 B4 FB CE 00 00 80 31 00 00 01 2C 00 01 00 01 58 CE C1 8D 7A 3F 2D 40 AB F0 E5 40 00 A2 13 00 00 00 04 02 00 FF 33
Correct answer cluster ID: 0x 80 31
Focussing on the RF Data i have the following:
2C 00 01 00 01 58 CE C1 8D 7A 3F 2D 40 AB F0 E5 40 00 A2 13 00 00 00 04 02 00 FF
I now try to decode this hex string and face some problems.
From my point of view, this string should be encoded like defined within the ZigBee Spec from 2012, at Table 2.126 and 2.127
Unfortunately this don´t work for me. If i ignore, that the first byte should be the status and take the first two of them, i can read out NeighborTableEntries, StartIndex, NeighborTabelListCount. But when it comes to the NeighTableList i only can read out the Extended PAN id, the extended address and the network address, the rest of the string does not fit to the standard. Am i doing something wrong here or does the xbee´s don´t stick to the standard?
2C = Sequence Number
00 = Status (Success)
01 = 1 entry (total)
00 = starting at index 0
01 = 1 entry (in packet)
58 CE C1 8D 7A 3F 2D 40 = Extended Pan ID
AB F0 E5 40 00 A2 13 00 = IEEE address
00 00 = NodeId
04 = (Coordinator, RxOnWhenIdle)
02 = (Unknown Permit Join)
00 = (Coordinator)
FF = (LQI)
The values after the NodeId are bitmasks, not bytes.
Related
I am writing a guest OS on top of Linux (Ubuntu distribution) within a Docker container. The filesystem is implemented as a single file resting inside the host OS, so anytime a file is changed in the guest OS filesystem, the file on the host OS must be opened, the correct block(s) must be overwritten, and the file must be closed.
My partner and I have developed the following recursive helper function to take in a block number and offset to abstract away all details at the block-level for higher level functions:
/**
* Recursive procedure to write n bytes from buf to the
* block specified by block_num. Also updates FAT to
* reflect changes.
*
* #param block_num identifier for block to begin writing
* #param buf buffer to write from
* #param n number of bytes to write
* #param offset number of bytes to start writing from as
* measured from start of file
*
* #returns number of bytes written
*/
int write_bytes(int block_num, const char *buf, int n, int offset) {
BlockTuple red_tup = reduce_block_offset(block_num, offset);
block_num = red_tup.block;
offset = red_tup.offset;
FILE *fp = fopen(fat->fname, "r+");
int bytes_to_write = min(n, fat->block_size - offset);
int write_n = max(bytes_to_write, 0);
fseek(fp, get_block_start(block_num) + offset, SEEK_SET);
fwrite(buf, 1, write_n, fp); // This line is returning 48 bytes written
fclose(fp);
// Check if there are bits remaining
int bytes_left = n - write_n;
if (bytes_left > 0) {
// Recursively write on next block
int next_block = get_free_block();
set_fat_entry(block_num, next_block); // point block to next block
set_fat_entry(next_block, 0xFFFF);
return write_bytes(next_block, buf + write_n, bytes_left, max(0, offset - fat->block_size)) + write_n;
} else {
set_fat_entry(block_num, 0xFFFF); // mark file as terminated
return write_n;
}
}
The issue is that fwrite(3) is reporting 48 bytes written (when n is passed as 48) but hexdumping the file on the host OS reveals no bytes have been changed:
00000000 00 01 ff ff ff ff 00 00 00 00 00 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00008000
This is particularly wacky because when my partner runs the code on the exact same commit (with no uncommitted changes), her write goes through and the file on the host OS hexdumps to:
00000000 00 01 ff ff ff ff 00 00 00 00 00 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000100 66 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |f1..............|
00000110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000120 00 01 00 00 02 00 01 06 e7 36 75 63 00 00 00 00 |.........6uc....|
00000130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000200 e0 53 f8 88 c0 0d 37 ca 84 1f 19 b0 6c a8 68 7b |.S....7.....l.h{|
00000210 57 83 cf 13 f0 42 21 d3 21 e1 da de d4 8a f1 e6 |W....B!.!.......|
00000220 f0 12 98 fb 1c 30 4c 04 b3 16 1d 96 17 ba d7 5a |.....0L........Z|
00000230 7e f3 8a f5 6a 42 6b ef 58 f6 bc 01 db 0c 02 53 |~...jBk.X......S|
00000240 e5 10 7e f3 4a d5 3f ac 8e 38 82 c3 95 f8 11 8e |..~.J.?..8......|
00000250 a6 82 eb 3b 24 56 9a 75 44 36 8b 25 60 83 4c 04 |...;$V.uD6.%`.L.|
00000260 07 9e 14 99 9c 9f 87 3c 8a d4 c3 e8 17 60 81 0e |.......<.....`..|
00000270 bc eb 1d 35 68 fc d5 be 4f 1c 9d 5e 72 57 65 01 |...5h...O..^rWe.|
00000280 b7 43 54 26 d6 6d ba 51 bf 12 8c a1 03 d5 66 b3 |.CT&.m.Q......f.|
00000290 90 0d 60 b8 95 8d 15 bd 53 9a 70 77 4f 7a 04 1e |..`.....S.pwOz..|
000002a0 9e b2 4c 9a 79 dd de 48 cd fe 1e dc 57 7d d1 7f |..L.y..H....W}..|
000002b0 3f f5 77 96 fa e7 d7 33 33 48 ce 0a 4d 61 ab 96 |?.w....33H..Ma..|
000002c0 5f c4 88 bf c6 3a 09 37 76 c4 b8 db bc 6a 7d c0 |_....:.7v....j}.|
000002d0 c4 89 68 e7 b4 70 f8 a6 a8 00 9d c4 63 da fb 66 |..h..p......c..f|
000002e0 be d2 cd 68 1c d2 ff bf 00 e9 37 ab 6b 1a 3c f2 |...h......7.k.<.|
000002f0 7b c1 a2 c4 46 ae db 93 b4 4f 64 79 14 2a 1a d4 |{...F....Ody.*..|
00000300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00008000
The 48 bytes I'm referring to that don't get written are the bytes written to the directory block running from address 00000100-0000012E (the bytes below that represent the actual file being written, the code seg faults on my end before reaching that write). It's worth noting my container can still format the filesystem file, so all writes aren't broken. This snippet just represents the first write that did not work.
We are both running the code in an identical Docker container. The only difference I could imagine is my computer is a Windows and hers is a Mac. What could possibly be the issue?
The very first thing I believed was that there was some conflict with the host OS that blocked my write, but assigning and printing the return value of fwrite(3) returned that 48 bytes were indeed written on both machines.
I was also expecting that my buffer was simply all 0s (it is initially allocated using calloc(3)), but printing out the first 48 bytes of the buffer proved that theory false.
I finally considered that this was some issue with the higher level interface in <stdio.h> instead of the lower level one in <unistd.h>. I replaced fopen(3), fwrite(3), flseek(3), fclose(3) each with their lower-level equivalents (write(2) etc) and it still turned up 48 bytes written with no actual change to the files.
EDIT:
The guest OS filesystem can be formatted with respect to user parameters. All testing above was performed with a block size of 256 bytes and 128 blocks total. I've attempted the exact same write sequence again with a block size of 1024 bytes and 16384 blocks total, and there was no error. It's still unclear why the code works on my partner's machine for both format configs and not mine, but this may narrow it down.
Running strace reveals the following excerpt around the write:
openat(AT_FDCWD, "minfs", O_RDWR) = 4
newfstatat(4, "", {st_mode=S_IFREG|0777, st_size=32768, ...}, AT_EMPTY_PATH) = 0
lseek(4, 0, SEEK_SET) = 0
read(4, "\0\1\377\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 256) = 256
write(4, "f1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 48) = 48
close(4)
It again appears the bytes get written, but a hd after the program finishes reveals the same output as above. My thought was perhaps the bytes written in the excerpt are overwritten later on, but the only write after the excerpt above in the strace is:
lseek(4, 0, SEEK_SET) = 0
read(4, "\0\1\377\377\377\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 320) = 320
write(4, "\0", 1) = 1
close(4)
which should be at address 320, squarely after the write at address 256 above.
It turns out the mismatch was due to undefined behavior concerning when changes were synchronized in mmap(2). There was a section of code where a region of memory mapped via mmap(2) was changed and then immediately followed by reads/writes to the file on the host OS containing the mapped region of memory. It seems the Mac would write through the changes before the following section while the Windows wouldn't synchronize until after the fact, resulting in the undefined behavior.
The problem was fixed by making a call to msync(2) immediately after modifying the mapped region from mmap(2) with the MS_SYNC flag forcing the write-through behavior.
Links to documentation here: mmap(2), msync(2).
I'm using the ATSAMV71Q21B MCU which uses a cortex-M7 processor. In order to add redundancy, I would like to have multiple boot loader and enter to one of those boot loader just after starting the microcontroller. Atlough, the ARM processor begins executing at the reset vector location 0x00000000. I cannot choose where I want to start.
I was wondering if it was possible to branch to one of my boot loaders using in few instructions.
For the moment, all solutions that I tried to generate hundred instructions which is too much for me. I guess that I need to manually add branch instructions the vector location 0x00000000. Although, I'm not sure where I should branch and if it is OK to do this.
Indeed, I'm not sure if I really understand the beginning of the assembly code generated. Therefore, I'm not sure where to branch.
Here is an example of the beginning of the program:
0x00400000 70 0a 40 20 d9 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 00 00 00 00 p.# Ù.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.....
0x00400020 00 00 00 00 00 00 00 00 00 00 00 00 d5 01 40 00 d5 01 40 00 00 00 00 00 d5 01 40 00 d5 01 40 00 ............Õ.#.Õ.#.....Õ.#.Õ.#.
0x00400040 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.
0x00400060 d5 01 40 00 00 00 00 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 Õ.#.....Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.
0x00400080 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.
0x004000A0 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.
0x004000C0 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.
0x004000E0 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.
0x00400100 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 00 00 00 00 00 00 00 00 Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.........
0x00400120 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.
0x00400140 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.
0x00400160 d5 01 40 00 d5 01 40 00 10 b5 05 4c 23 78 33 b9 04 4b 13 b1 04 48 af f3 00 80 01 23 23 70 10 bd Õ.#.Õ.#..µ.L#x3..K.±.H¯ó.€.##p..
0x00400180 2c 04 40 20 00 00 00 00 28 04 40 00 0c 4b 43 b1 0c 48 0d 49 10 b5 af f3 00 80 0c 48 03 68 23 b9 ,.# ....(.#..KC±.H.I.µ¯ó.€.H.h#.
0x004001A0 10 bd 0a 48 03 68 33 b9 70 47 09 4b 00 2b f7 d0 bd e8 10 40 18 47 06 4b 00 2b f5 d0 18 47 00 bf ...H.h3.pG.K.+÷Ð.è.#.G.K.+õÐ.G.¿
0x004001C0 00 00 00 00 28 04 40 00 30 04 40 20 28 04 40 00 00 00 00 00 fe e7 00 bf 16 49 17 4a 91 42 08 b5 ....(.#.0.# (.#.....þç.¿.I.J‘B.µ
If I understand correctly, this is a vector table and I should not branch here. Is that correct ?
0x00400000 70 0a 40 20 d9 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 00 00 00 00 p.# Ù.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.....
0x00400020 00 00 00 00 00 00 00 00 00 00 00 00 d5 01 40 00 d5 01 40 00 00 00 00 00 d5 01 40 00 d5 01 40 00 ............Õ.#.Õ.#.....Õ.#.Õ.#.
0x00400040 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.
0x00400060 d5 01 40 00 00 00 00 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 Õ.#.....Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.
0x00400080 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.Õ.#.
So these look fine the first one is the stack pointer load value
0x20400a70
A strange number perhaps but this part has 0x80000 bytes of ram so it is valid. so probably a linker script generated value (stack setup in the linker script rather than just start with top of ram).
Reset vector is
0x004001d9
which is properly formatted (lsbit is set) as to what it points to you have not provided.
many of the others are
0x004001d5
Also properly formatted is probably an infinite loop based on its proximity to the reset vector but who knows have to look at the code. It does not matter much for booting.
The chip/family doc indicates that user flash is at address 0x00400000 and is quite large for these parts, so both the address on the left of this dump and the reset vectors this all looks fine.
There is an indication that there is a sam-ba bootloader at some address 0x00800000 or 0x08000000 or I do not remember, you can look it up. Now I have used other Atmel parts that did not have the bootloader burned in the flash from Atmel but instead source to a sam-ba you could build and use yourself (why bother make your own much simpler less bulky), but I had issues with that approach how the flash did or didn't lock, how easy to unlock and erase, so what is the point? use SWD. This comment in the doc may indicate a burned in one in that case then you need to look at how to choose to boot that application instead of the user application, in either case since they indicate a specific address. If it is user changeable then that would be where you want to put your bootloader possibly or if fixed and not changeable then just use it as your bootloader.
As to where in general you put your bootloader that is all you, you choose your design, what you mean by bootloader, what features etc. Often misused but the term implies both booting the part but also having a way to load other applications in some way (run one in ram, reprogram the user/boot/application flash, etc). Something you need to look at is how the flash works on this device assuming you want to be able to re-write a portion of it with new firmware. Sometimes you can execute out of and flash at the same time but more likely to do that they use multiple flash banks so you can run in one and modify the other, which then leads into what is their boot scheme does it always only boot on one and never the other so you either have to keep the bootloader as-is forever or have a scheme, also have to have a scheme for choosing which of the images on which banks to be the default firmware after the bootloader boots.
These cores can run code in ram generally and no reason to expect not here (it's not the core, it's the chip vendor's implementation that matters) so doing a copy and jump of a portion of the bootloader to ram in order to not be running on flash allowing you to reprogram any of the flash but put yourself at risk if it fails or if power goes the part may be bricked.
If the chip vendor has not already done this with a factory bootloader and that factory loader being desirable for field use, it may use an I/O pin to determine which one boots, have to look at the docs. If you choose to do this yourself it is not unwise to have a gpio pin pick two boot paths, you can then have a very small, ideally bug free dozen or so lines of assembly that read the gpio pin and branch to a fixed point in flash that you choose Say 0x00500000 and 0x00600000 for example depending on how big you think your applications really will be. Then you can do a copy and jump into ram if the user desires loading the flash and then you can choose to load one or the other. The handful of lines of code could be a few dozen and do a checksum of some sort of the selected bank and the not selected if the selected is bad and did not complete. or a third bootloader that you provide in case the two do not checksum.
Tons of solutions, generally if you do not have separately banked flashes you need to branch to ram and have more freedom as to how to design your memory space (assuming the flash can be erased in pages). Otherwise you might want to just go with the banking solution from the chip vendor.
So all of this is documented in documents from arm and Atmel (microchip) that you should have had before starting work on this device. The only thing remotely related to arm in any of this is how the vector table works. All of the rest, the addresses, sizes, etc are all chip vendor implementation. So most of your reading is in the chip vendors docs, in this case they have the huge datasheet approach (rather than separate data sheet and reference manual approach).
You need to re-read what I found about sam-ba if you want to use that if it works for you, the nature of the flash implementation, is it in application programmable, etc. And then you design not only the functionality of your bootloader but the address space, whether it executes in flash or ram.
Edit
In case I did not understand the question.
The arm reset vector is at 0x00000004 not 0x00000000 (for the cortex-ms) and it is the address of the handler ORRED with one. Address 0x00000000 is the stack pointer initialization value, if you choose to init the stack pointer in code and not using this mechanism you can put whatever you want there.
If you want to change the reset handler address then you have to modify 0x00000004 which on some parts you can change without an erase (often flashes either work by erasing to all ones then you can write zeros, can't write ones but can changes ones to zeros on a per byte/word/chunk basis). So to change this you likely need to save it erase the block/page, change the bits you want and write back. You might for example be able to change it from 0x004001d9 to sah 0x004101d9 or to 0x004000d9, but not worth trying to do that. The value is the address of the handler ORRED with one.
It is not a branch as code is not executing at this point (normally/assumed) it is the logic reading that location and using that as the starting point, the first fetch not branch.
And as pointed out look at where the vector table is in the project and then modify that to point at your alternate reset handler. It might be code that looks like this
.word STACK_END
.word reset_handler
.word
in this case some fill/dummy vector for many of the rest. Just replace the reset_handler or whatever you find with your handler, remember this is a bootloader and you need to bootstrap C if you plan to call any C functions, worse if C++ or other language.
I have an MPEG file which starts like this:
0: 00 0f 6d 79 5f 66 69 6c 65 6e 61 6d 65 2e 6d 70 ..my_filename.mp
10: 67 00 04 fc 00 00 f0 00 b2 10 39 a8 b2 10 39 ad g.........9...9.
20: 0f 6d 79 5f 66 69 6c 65 6e 61 6d 65 2e 6d 70 67 .my_filename.mpg
30: 03 92 3b 40 00 00 00 00 03 7a b5 7c 03 7a d7 d0 ..;#.....z.|.z..
40: 00 4d 6f 6f 56 54 56 4f 44 01 00 01 2a 00 80 00 .MooVTVOD...*...
50: 00 00 00 00 36 b2 83 00 00 04 fc b2 10 39 a8 b2 ....6........9..
60: 10 39 ad 00 00 00 00 00 00 00 00 00 00 00 00 00 .9..............
70: 00 00 00 00 00 00 00 00 00 00 81 81 35 d3 00 00 ............5...
80: 00 36 b2 83 6d 64 61 74 00 00 01 ba 21 00 01 00 .6..mdat....!...
90: 05 80 2b 81 00 00 01 bb 00 0c 80 2f d9 04 e1 ff ..+......../....
a0: c0 c0 20 e0 e0 2e 00 00 01 c0 07 ea ff ff ff ff .. .............
What is the file format of the beginning of the file (first 0x80 bytes), and how do I parse it?
I've run a Google search on MooVTVOD, it looks like something related to QuickTime and iTunes.
What I understand already:
There is 4 bytes of big endian file size in front mdat, according to the QuickTime .mov file format when the .mov contains an MPEG.
Right after mdat there is the MPEG-PS header 00 00 01 ba. Shortly after there is the MPEG-PES header 00 00 01 c0 indicating an audio stream.
However, the first 0x80 bytes in this file seem to be in a different file file format (not QuickTime .mov, not MPEG-PS, not MPEG-PES), and in this question I'm only interested in the file format of the first 0x80 bytes.
Media players such as VLC routinely ignore junk at the beginning of the file, and start playing the MPEG-PS stream at offset 0x80. However, I'm interested in the 0x80 bytes they ignore.
The file format is "Quicktime movie atom," that contains meta information about the media file, or the media itself. mdat is a Media Data atom.
Media atoms describe and define a track’s media type and sample data.
the spec is here: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html
You can parse it with this python script:
https://github.com/kzahel/quicktime-parse
or this software, mentioned in the linked question:
https://archive.codeplex.com/?p=mp4explorer
The file format of the first 0x80 bytes in the question is MacBinary II.
Based on the file format description https://github.com/mietek/theunarchiver/wiki/MacBinarySpecs , it's not MacBinary I, because MacBinary II has data[0x7a] == '\x81' and data[0x7b] == '\x81' (and MacBinary I has data[0x7a] == '\x00', and MacBinary III has data[0x7a] == '\x82'); and it's also not MacBinary III, because that one has data[0x66 : 0x6a] == 'mBIN'.
The CRC value data[0x7c : 0x7e] is incorrect because the filename was modified before posting to StackOverflow. FYI The CRC algorithm used is CRC16/XMODEM (on https://crccalc.com/), also implemented as CalcCRC in
MacBinary.c.
The data[0x41 : 0x45] == 'MooV' is the file type code. According to the Excel spreadsheet downloadable from TCDB, it means QuickTime movie (video and maybe audio).
The data[0x45 : 0x49] == 'TVOD' is the file creator code. TCDB and this database indicate that it means QuickTime Player.
More info and links about MacBinary: http://fileformats.archiveteam.org/wiki/MacBinary
Please note that all these headers are unnecessary to play the video: by removing the first 0x88 bytes we get an MPEG-PS video file, which many video players can play (not only QuickTime Player, and not only players running on macOS).
I' m working on Mastercard Paypass transactions, I Have sent a READ RECORD command and got the result:
70 81 AB 57 11 54 13 33 00 89 60 10 83 D2 51 22
20 01 23 40 91 72 5A 08 54 13 33 00 89 60 10 83
5F 24 03 25 12 31 5F 25 03 04 01 01 5F 28 02 00
56 5F 34 01 01 8C 21 9F 02 06 9F 03 06 9F 1A 02
95 05 5F 2A 02 9A 03 9C 01 9F 37 04 9F 35 01 9F
45 02 9F 4C 08 9F 34 03 8D 0C 91 0A 8A 02 95 05
9F 37 04 9F 4C 08 8E 0E 00 00 00 00 00 00 00 00
42 03 5E 03 1F 03 9F 07 02 FF 00 9F 08 02 00 02
9F 0D 05 00 00 00 00 00 9F 0E 05 00 08 00 60 00
9F 0F 05 00 00 00 00 00 9F 42 02 09 78 9F 4A 01
82 9F 14 01 00 9F 23 01 00 9F 13 02 00 00
This response contains TLV data objects (without spaces). I have converted the response as described in the following:
// Read Record 1 with SFI2
//---------------------------------SEND READ RECORD-------------------
inCtlsSendVAPDU(0x2C,0x03,(unsigned char *)"\x00\xB2\x01\x14\x00",5);
clrscr();
inRet = inCTLSRecv2(Response, 269);
LOG_HEX_PRINTF("Essai EMV4 Read record 1 EMV Paypass:",Response,inRet);
if(Response[14]==0x70)
{
sprintf(Response_PPSE,"%02X%02X",Response[12],Response[13]);//To retrieve length of received data
t1=hexToInt(Response_PPSE);// Convert length to integer
t11=t1-2;
i=14;
k=0;
//--------------------------- Converting data to be used later---------
while(i<t11+14)// 14 to escape the header+ command+ status+ length
{
sprintf(READ1+(2*k),"%02X",Response[i]);
i++;
k++;
}
Now I should check if this Response contains the Mandatory Tags:
5A - Application Primary Account Number (PAN)
5F24 - Application Expiration Date
8C - Card Risk Management Data Object List 1 (CDOL1)
8D - Card Risk Management Data Object List 2 (CDOL2)
So I tried the following to check for the 5A tag (Application Primary Account Number (PAN)):
i=0;
t11=2*t11;
while(i<=t11)
{
strncpy(Response_PPSE,READ1+i,2);
if(strncmp(Response_PPSE,"\x05\x0A")==0)
{
write_at("true",4,1,1);// Just to test on the terminal display
goto end;
}
else
i=i+2;
}
goto end;
I don't know why nothing is displayed on the terminal, The if block is not executed!
I tried to print the 5A tag manually by:
strncpy(Response_PPSE,READ1+44,2);
write_at(Response_PPSE,strlen(Response_PPSE),1,1);
And it display the right value!!
Can someone helps to resolve this issue?
You don't find that tag because you are not searching for the string "5A" but for the string "\x05\x0A" (ENQ character + line feed character). Moreover, I wonder if the above code actually compiles as you did not specify the mandatory length argument to strncmp(). You could try something like
if(strncmp(Response_PPSE,"5A", 2)==0)
instead.
However, you should understand that you are scanning the whole response data for the value 5A. Therefore, finding this value could also mean that it was part of some other TLV tag's data field, length field or even part of a multi-byte tag field. It would therefore make sense to implement (or use an existing) TLV parser for the BER (Basic Encoding Rules) format.
It's not a good approach to search a specific byte in a raw byte-stream data using strings functions at first place.
The generic TLV parser is a very easy algorithm and you will do it in 30 minutes or so.
In general a pseudo-code for TLV parser that look for a specific Tag would be something like this:
index = 0
while (byte[i] != 0x5A or EOF)
{
length = DecodeLength(byte[i+1])
i += length + 2 // + 1 for L (length) byte itself, it might be encoded with
// 2 bytes so the function DecodeLength can return the number
// of bytes lenght has been encoded
// +1 for T (tag) byte
}
if(EOF) return tag_not_found
return byte[i + 2], length // pointer to data for Tag '5A'and length of data
We see these packets being injected in an FTP-DTP channel during a downlink file transfer on Telstra's NEXTG mobile network. We are not sure if these are network level packets, a problem with our 3G modem (HC25 based) or something like our firewall injecting in the stream.
Using a tool we noticed that the PPP framing fails with protocol length errors, so they are mostly likely mobile network packets.
I am hoping someone here can identify the signature of the packets so that I can chase this up with the appropriate vendor.
There is definitely a format to these packets: -
Packet1:
00 00 00 24 c4 b8 7b 1a 00 90 7f 43 0f a1 08 00 45 00 01 10 f4 4e 00 00 40 06 2f 13 cb 7a 9d e9 7b d0 71 52 7a ed 04 06 8c 61 5d a9 01 f7 0c eb 50 10 ff ff 58 b9 00 00
Packet2:
00 00 00 24 c4 b8 7b 1a 00 90 7f 43 0f a1 08 00 45 00 00 ff 6b 50 00 00 40 06 b8 22 cb 7a 9d e9 7b d0 71 52 7a ed 04 06 8c 61 7b 82 01 f7 0c eb 50 10 ff ff a3 79 00 00
Packet3:
00 00 00 24 c4 b8 7b 1a 00 90 7f 43 0f a1 08 00 45 00 02 20 5b 50 00 00 40 06 c7 01 cb 7a 9d e9 7b d0 71 52 7a ed 04 06 8c 61 7c 59 01 f7 0c eb 50 10 ff ff e2 5d 00 00
Packet4:
00 00 00 24 c4 b8 7b 1a 00 90 7f 43 0f a1 08 00 45 00 01 38 d8 52 00 00 40 06 4a e7 cb 7a 9d e9 7b d0 71 52 7a ed 04 06 8c 62 42 f9 01 f7 0c eb 50 10 ff ff 20 91 00 00
Packet5:
00 00 00 24 c4 b8 7b 1a 00 90 7f 43 0f a1 08 00 45 00 00 d0 4d 58 00 00 40 06 d6 49 cb 7a 9d e9 7b d0 71 52 7a ee 04 08 4b fb 0b 8f 03 5d 51 1a 50 10 ff ff e9 88 00 00
I converted your packet trace snippet into a format understood by text2pcap so I could convert them into the pcap format for viewing in Wireshark (a very handy packet capture and analysis tool):
Looks like some sort of IPv4 multicast traffic at a very rough guess. Here's what I got from the first packet (rest came up as malformed):
No. Time Source Destination Protocol Info
1 0.000000 7b:1a:00:90:7f:43 00:00:00_24:c4:b8 0x0fa1 Ethernet II
Frame 1 (31 bytes on wire, 31 bytes captured)
Arrival Time: Dec 1, 2009 00:33:05.000000000
[Time delta from previous captured frame: 0.000000000 seconds]
[Time delta from previous displayed frame: 0.000000000 seconds]
[Time since reference or first frame: 0.000000000 seconds]
Frame Number: 1
Frame Length: 31 bytes
Capture Length: 31 bytes
[Frame is marked: False]
[Protocols in frame: eth:data]
Ethernet II, Src: 7b:1a:00:90:7f:43 (7b:1a:00:90:7f:43), Dst: 00:00:00_24:c4:b8 (00:00:00:24:c4:b8)
Destination: 00:00:00_24:c4:b8 (00:00:00:24:c4:b8)
Address: 00:00:00_24:c4:b8 (00:00:00:24:c4:b8)
.... ...0 .... .... .... .... = IG bit: Individual address (unicast)
.... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
Source: 7b:1a:00:90:7f:43 (7b:1a:00:90:7f:43)
Address: 7b:1a:00:90:7f:43 (7b:1a:00:90:7f:43)
.... ...1 .... .... .... .... = IG bit: Group address (multicast/broadcast)
.... ..1. .... .... .... .... = LG bit: Locally administered address (this is NOT the factory default)
Type: Unknown (0x0fa1)
Data (17 bytes)
0000 08 00 45 00 01 10 f4 4e 00 00 40 06 2f 13 cb 7a ..E....N..#./..z
0010 9d .
Data: 080045000110F44E000040062F13CB7A9D
These look like ordinary TCP packets but with two extra 00 bytes tagged on at the front. Not sure why that would happen, but they appear to be from 00-90-7f-43-0f-a1 (Watchguard) to 00-24-c4-b8-7b-1a (Cisco).
IP header is 45 00 01 10 f4 4e 00 00 40 06 2f 13 cb 7a 9d e9 7b d0 71 52
TCP header is 7a ed 04 06 8c 61 5d a9 01 f7 0c eb 50 10 ff ff 58 b9 00 00
So you can get the rest of the details from there.
00:24:c4 is a NIC from Cisco and 00:90:7F is a NIC from WatchGuard.
From the IEEE OUI Registry.
How much help that might be ... don't know. Might therefore be an attempted VPN connection.
As already decoded by others:
first 6+6+2 bytes identifying NIC and Ethernet II.
bytes 0x0800 EtherType telling that it is IP. http://en.wikipedia.org/wiki/EtherType
next octet starting with nibble "4" is IPv4
etc.