I am trying to implement creating an image file in C. The format of the image I want to be is RGB565. I have followed these two websites 1 2 to try and get a viewable image but I do not seem to get it working. Is the problem in the "fwrite" function because of the little endian thing?
For testing purposes I want an image that is 16*4 large and all pixels are of the same color. (The code is a mess as it is just for testing purposes before implementing it in a bigger project.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
int main() {
uint16_t myData[64];
for(int i = 0; i<64; i++)
{
myData[i] = 0x241B; //Random Color
}
typedef struct /**** BMP file header structure ****/
{
uint16_t bfType; /* Magic number for file */
uint32_t bfSize; /* Size of file */
uint16_t bfReserved1; /* Reserved */
uint16_t bfReserved2; /* ... */
uint32_t bfOffBits; /* Offset to bitmap data */
} BITMAPFILEHEADER;
typedef struct /**** BMP file info structure ****/
{
uint32_t biSize; /* Size of info header */
uint32_t biWidth; /* Width of image */
uint32_t biHeight; /* Height of image */
uint16_t biPlanes; /* Number of color planes */
uint16_t biBitCount; /* Number of bits per pixel */
uint32_t biCompression; /* Type of compression to use */
uint32_t biSizeImage; /* Size of image data */
uint32_t biXPelsPerMeter; /* X pixels per meter */
uint32_t biYPelsPerMeter; /* Y pixels per meter */
uint32_t biClrUsed; /* Number of colors used */
uint32_t biClrImportant; /* Number of important colors */
} BITMAPINFOHEADER;
BITMAPFILEHEADER myFileHeader = {0x4D42, 198, 0, 0, 70};
BITMAPINFOHEADER myInfoHeader = {40, 16, 4, 1, 16, 0, 0, 1000, 1000, 0, 0};
uint32_t RGB565ColorTable[] = {0x7E00000, 0xF8000000, 0x001F0000, 0};
FILE *fptr; fptr = fopen("testImage.bmp","w+");
if(fptr == NULL) {
printf("Error!");
exit(1); }
fwrite(&myFileHeader, sizeof(BITMAPFILEHEADER), 1, fptr);
fwrite(&myInfoHeader, sizeof(BITMAPINFOHEADER), 1, fptr);
fwrite(&RGB565ColorTable, sizeof(RGB565ColorTable), 1, fptr);
fwrite(&myData, sizeof(myData), 1, fptr);
fclose(fptr);
return 0; }
Hex Output (after adding attribute((packed)) to structs ):
I did clean up the code. And it looks like it is working:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct /**** BMP file header structure ****/
{
uint16_t bfType; /* Magic number for file */
uint32_t bfSize; /* Size of file */
uint16_t bfReserved1; /* Reserved */
uint16_t bfReserved2; /* ... */
uint32_t bfOffBits; /* Offset to bitmap data */
} __attribute__((packed)) BITMAPFILEHEADER;
typedef struct /**** BMP file info structure ****/
{
uint32_t biSize; /* Size of info header */
uint32_t biWidth; /* Width of image */
uint32_t biHeight; /* Height of image */
uint16_t biPlanes; /* Number of color planes */
uint16_t biBitCount; /* Number of bits per pixel */
uint32_t biCompression; /* Type of compression to use */
uint32_t biSizeImage; /* Size of image data */
uint32_t biXPelsPerMeter; /* X pixels per meter */
uint32_t biYPelsPerMeter; /* Y pixels per meter */
uint32_t biClrUsed; /* Number of colors used */
uint32_t biClrImportant; /* Number of important colors */
} __attribute__((packed)) BITMAPINFOHEADER;
int main()
{
FILE *fptr;
BITMAPFILEHEADER myFileHeader = {
.bfType = 0x4D42,
.bfSize = 198,
.bfOffBits = 70
};
BITMAPINFOHEADER myInfoHeader = {
.biSize = 40,
.biWidth = 16,
.biHeight = 4,
.biPlanes = 1,
.biBitCount = 16,
.biCompression = 0,
.biSizeImage = 0,
.biXPelsPerMeter = 1000,
.biYPelsPerMeter = 1000,
.biClrUsed = 0,
.biClrImportant = 0
};
uint32_t RGB565ColorTable[] = {
0x7E00000, 0xF8000000, 0x001F0000, 0
};
uint16_t myData[64];
for(int i = 0; i<64; i++)
{
myData[i] = 0x241B; //Random Color
}
fptr = fopen("testImage.bmp","w+");
if(fptr == NULL) {
printf("Error!");
exit(1);
}
fwrite(&myFileHeader, sizeof(myFileHeader), 1, fptr);
fwrite(&myInfoHeader, sizeof(myInfoHeader), 1, fptr);
fwrite(&RGB565ColorTable, sizeof(RGB565ColorTable), 1, fptr);
fwrite(&myData, sizeof(myData), 1, fptr);
fclose(fptr);
return 0;
}
I do have the following output :
hexdump -C testImage.bmp
00000000 42 4d c6 00 00 00 00 00 00 00 46 00 00 00 28 00 |BM........F...(.|
00000010 00 00 10 00 00 00 04 00 00 00 01 00 10 00 00 00 |................|
00000020 00 00 00 00 00 00 e8 03 00 00 e8 03 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 e0 07 00 00 00 f8 00 00 |................|
00000040 1f 00 00 00 00 00 1b 24 1b 24 1b 24 1b 24 1b 24 |.......$.$.$.$.$|
00000050 1b 24 1b 24 1b 24 1b 24 1b 24 1b 24 1b 24 1b 24 |.$.$.$.$.$.$.$.$|
*
000000c0 1b 24 1b 24 1b 24 |.$.$.$|
You need to pack the file header struct so that the compiler won't pad the entries. You can use __attribute__((packed)) with gcc when defining the structs to accomplish this.
With MSVC you can enclose a struct with
#pragma pack(push, 1)
// struct
#pragma pack(pop)
to make it packed. I have found it is only needed for BITMAPFILEHEADER on a 32-bit compilation.
Related
I keep receiving fragment udp packets and do reassemble two fragment packets to one, it become multi-seg packet, and then send to another NIC,
(NIC 710 port0 -> do reassembel -> NIC 710 port1 -> NIC 710 port1 recevice packets -> do fragment -> NIC 710 port0)
I receive a strange packet which only have one segment, but m-> next is not NULL.
so after pkt_len minus two times, pkt_len become underflow,
this problem run about 5.5hours ocuur, how to prevent this problem?
platform:
OS: Ubuntu 18.04
kernel version: Linux mec 4.15.0-112-generic
DPDK version: DPDK 19.11.11 (LTS)
NIC: Intel 710
NIC firmware:
mec#mec:~$ sudo lshw -c Network | grep X710 -B10
*-network:0 DISABLED
description: Ethernet interface
product: Ethernet Controller X710 for 10GbE SFP+
--
version: 02
serial: f8:f2:1e:58:9b:b0
size: 10Gbit/s
width: 64 bits
clock: 33MHz
capabilities: pm msi msix pciexpress vpd bus_master cap_list rom ethernet physical fibre autonegotiation
configuration: autonegotiation=off broadcast=yes driver=i40e driverversion=2.1.14-k duplex=full firmware=6.80 0x80003d73 18.8.9 latency=0 link=no multicast=yes port=fibre speed=10Gbit/s
resources: irq:97 memory:93000000-93ffffff memory:94018000-9401ffff memory:94100000-9417ffff
*-network:1 DISABLED
description: Ethernet interface
product: Ethernet Controller X710 for 10GbE SFP+
--
version: 02
serial: f8:f2:1e:58:9b:b1
size: 10Gbit/s
width: 64 bits
clock: 33MHz
capabilities: pm msi msix pciexpress vpd bus_master cap_list rom ethernet physical fibre autonegotiation
configuration: autonegotiation=off broadcast=yes driver=i40e driverversion=2.1.14-k duplex=full firmware=6.80 0x80003d73 18.8.9 latency=0 link=no multicast=yes port=fibre speed=10Gbit/s
resources: irq:97 memory:92000000-92ffffff memory:94010000-94017fff memory:94180000-941fffff
*-network:2 DISABLED
description: Ethernet interface
product: Ethernet Controller X710 for 10GbE SFP+
--
version: 02
serial: f8:f2:1e:58:9b:b2
size: 10Gbit/s
width: 64 bits
clock: 33MHz
capabilities: pm msi msix pciexpress vpd bus_master cap_list rom ethernet physical fibre autonegotiation
configuration: autonegotiation=off broadcast=yes driver=i40e driverversion=2.1.14-k duplex=full firmware=6.80 0x80003d73 18.8.9 latency=0 link=no multicast=yes port=fibre speed=10Gbit/s
resources: irq:97 memory:91000000-91ffffff memory:94008000-9400ffff memory:94200000-9427ffff
*-network:3 DISABLED
description: Ethernet interface
product: Ethernet Controller X710 for 10GbE SFP+
mec#mec:~$ sudo ethtool -i enp3s0f0
driver: i40e
version: 2.1.14-k
firmware-version: 6.80 0x80003d73 18.8.9
expansion-rom-version:
bus-info: 0000:03:00.0
supports-statistics: yes
supports-test: yes
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: yes
int rte_mbuf_check_handmade1(const struct rte_mbuf *m, int is_header,
const char **reason)
{
unsigned int nb_segs, pkt_len;
if (m == NULL) {
*reason = "mbuf is NULL";
return -1;
}
/* generic checks */
if (m->pool == NULL) {
*reason = "bad mbuf pool";
return -1;
}
if (m->buf_iova == 0) {
*reason = "bad IO addr";
return -1;
}
if (m->buf_addr == NULL) {
*reason = "bad virt addr";
return -1;
}
uint16_t cnt = rte_mbuf_refcnt_read(m);
if ((cnt == 0) || (cnt == UINT16_MAX)) {
*reason = "bad ref cnt";
return -1;
}
/* nothing to check for sub-segments */
if (is_header == 0)
return 0;
/* data_len is supposed to be not more than pkt_len */
if (m->data_len > m->pkt_len) {
*reason = "bad data_len";
return -1;
}
nb_segs = m->nb_segs;
pkt_len = m->pkt_len;
uint16_t port = m->port, data_len = m->data_len, ori_nb_segs = m->nb_segs, buf_len = m->buf_len;
uint32_t ori_pkt_len = m->pkt_len;
uint64_t ol_flags = m->ol_flags;
struct rte_mbuf* last_ptr;
// os_printf("before loop: ol_flags = %"PRIu64", port = %"PRIu16", data_len = %"PRIu16", pkt_len = %"PRIu32", nb_segs = %"PRIu16", buf_len = %"PRIu16"\n", m->ol_flags, m->port, m->data_len, m->pkt_len, m->nb_segs, m->buf_len);
do {
if (m->data_off > m->buf_len) {
*reason = "data offset too big in mbuf segment";
return -1;
}
if (m->data_off + m->data_len > m->buf_len) {
*reason = "data length too big in mbuf segment";
return -1;
}
os_log_debug("bf loop: ol_flags = %"PRIu64", port = %"PRIu16", data_len = %"PRIu16", pkt_len = %"PRIu32", nb_segs = %"PRIu16", buf_len = %"PRIu16"\n", m->ol_flags, m->port, m->data_len, m->pkt_len, m->nb_segs, m->buf_len);
nb_segs -= 1;
pkt_len -= m->data_len;
os_log_debug("in loop: ol_flags = %"PRIu64", port = %"PRIu16", data_len = %"PRIu16", pkt_len = %"PRIu32", nb_segs = %"PRIu16", buf_len = %"PRIu16"\n", m->ol_flags, m->port, m->data_len, pkt_len, nb_segs, m->buf_len);
last_ptr = (struct rte_mbuf* )m;
} while ((m = m->next) != NULL);
if(pkt_len){
os_printf("before loop: ol_flags = %"PRIu64", port = %"PRIu16", data_len = %"PRIu16", pkt_len = %"PRIu32", nb_segs = %"PRIu16", buf_len = %"PRIu16"\n", ol_flags, port, data_len, ori_pkt_len, ori_nb_segs, buf_len);
os_printf("after loop: pkt_len = %"PRIu32", nb_segs = %"PRIu16"\n", pkt_len, nb_segs);
if(last_ptr != NULL){
os_printf("last_ptr is not NULL and addr = %p\n", last_ptr);
} else {
os_printf("last_ptr is NULL\n");
}
}
if (nb_segs) {
*reason = "bad nb_segs";
return -1;
}
if (pkt_len) {
*reason = "bad pkt_len";
return -1;
}
return 0;
}
void
rte_mbuf_sanity_check_handmade1(const struct rte_mbuf *m, int is_header)
{
const char *reason;
if (rte_mbuf_check_handmade1(m, is_header, &reason)){
FILE* f = fopen("dumplog_sanity.txt", "w");
rte_pktmbuf_dump(f, m, rte_pktmbuf_pkt_len(m));
rte_pktmbuf_dump(stdout, m, rte_pktmbuf_pkt_len(m));
fclose(f);
rte_panic("%s\n", reason);
}
}
static inline char *rte_pktmbuf_adj_handmade(struct rte_mbuf *m, uint16_t len)
{
rte_mbuf_sanity_check_handmade1(m, 1);
uint16_t diff_of_len_data_len = len - m->data_len;
if (unlikely(len > m->data_len)){
os_printf("rte_pktmbuf_adj_handmade: get strange pkt!\n");
os_printf("len = %"PRIu16", m->data_len = %"PRIu16"\n", len, m->data_len);
os_printf("m->pkt_len = %"PRIu16", m-> data_off = %"PRIu16"\n", m->pkt_len, m->data_off);
return NULL;
}
/* NB: elaborating the addition like this instead of using
* += allows us to ensure the result type is uint16_t
* avoiding compiler warnings on gcc 8.1 at least */
uint16_t datalen,dataoff,pktlen;
datalen = (uint16_t)(m->data_len - len);
dataoff = (uint16_t)(m->data_off + len);
pktlen = (m->pkt_len - len);
if(0)
printf("%"PRIu16"%"PRIu16"%"PRIu16"%"PRIu16"",datalen,dataoff,pktlen,diff_of_len_data_len);
m->data_len = (uint16_t)(m->data_len - len);
m->data_off = (uint16_t)(m->data_off + len);
m->pkt_len = (m->pkt_len - len);
return (char *)m->buf_addr + m->data_off;
}
here is log
Jul 19 23:22:04 mec cht_mec_dp[3607]: bf loop: ol_flags = 449, port = 0, data_len = 70, pkt_len = 70, nb_segs = 1, buf_len = 2176
Jul 19 23:22:04 mec cht_mec_dp[3607]: in loop: ol_flags = 449, port = 0, data_len = 70, pkt_len = 0, nb_segs = 0, buf_len = 2176
Jul 19 23:22:04 mec cht_mec_dp[3607]: bf loop: ol_flags = 449, port = 0, data_len = 32, pkt_len = 32, nb_segs = 1, buf_len = 2176
Jul 19 23:22:04 mec cht_mec_dp[3607]: in loop: ol_flags = 449, port = 0, data_len = 32, pkt_len = 4294967264, nb_segs = 4294967295, buf_len = 2176
Jul 19 23:22:04 mec cht_mec_dp[3607]: before loop: ol_flags = 449, port = 0, data_len = 70, pkt_len = 70, nb_segs = 1, buf_len = 2176
Jul 19 23:22:04 mec cht_mec_dp[3607]: after loop: pkt_len = 4294967264, nb_segs = 4294967295
Jul 19 23:22:04 mec cht_mec_dp[3607]: last_ptr is not NULL and addr = 0x16dfb3300
Jul 19 23:22:04 mec cht_mec_dp[3607]: PANIC in rte_mbuf_sanity_check():
Jul 19 23:22:04 mec cht_mec_dp[3607]: bad nb_segs
here is my dump
dump mbuf at 0x16e49c9c0, iova=1fae49ca40, buf_len=2176
pkt_len=70, ol_flags=180, nb_segs=1, in_port=0
segment at 0x16e49c9c0, data=0x16e49cac0, data_len=70
Dump data at [0x16e49cac0], len=70
00000000: 34 17 EB 10 37 82 E4 43 4B 79 8C 20 81 00 01 2E | 4...7..CKy. ....
00000010: 08 00 45 00 00 34 B5 22 00 B9 40 11 47 43 0A 1E | ..E..4."..#.GC..
00000020: 04 5B 0A 1E 65 04 00 00 00 00 00 00 00 00 00 00 | .[..e...........
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
00000040: 00 00 00 00 00 00 | ......
dump mbuf at 0x16e4a38c0, iova=1fae4a3940, buf_len=2176
pkt_len=32, ol_flags=1c1, nb_segs=1, in_port=0
segment at 0x16e4a38c0, data=0x16e4a39e6, data_len=32
Dump data at [0x16e4a39e6], len=32
00000000: 00 00 00 00 00 00 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 | ................
I have verified in wireshark that my TCP handshake SYN+ACK packet after receiving SYN packet is getting ignored
This is wireshark main view that shows within time wireshark read my SYN+ACK packet for RTT. but my linux socket api function connect acting dummy and send SYN again, Wht I need to do in this case I am attaching my wireshark packet times plus actual communication packets, I need someone with knowledge of this and C to answer this very much thanks
This is recorded time in wireshark when packets in attempted handshake are read
This is received packet in my program code
SYN
0000 45 00 00 3c fa ed 40 00 40 06 aa 5a c0 a8 0a 14
0010 c0 a8 0a 0f bc be 00 50 f8 08 9d 5b 00 00 00 00
0020 a0 02 fa f0 bb 0f 00 00 02 04 05 b4 04 02 08 0a
0030 9a 68 0f b0 00 00 00 00 01 03 03 07
ACK SYN with valid checksums, sequence number and acknowledgement number
0000 45 00 00 28 00 64 40 00 40 06 a4 f8 c0 a8 0a 0f
0010 c0 a8 0a 14 00 50 bc be 00 00 00 03 f8 08 9d 5c
0020 50 12 fa f0 cc f6 00 00
And this is my linux connect function complete dummy behavior by sending SYN again
0000 45 00 00 3c fa ee 40 00 40 06 aa 59 c0 a8 0a 14
0010 c0 a8 0a 0f bc be 00 50 f8 08 9d 5b 00 00 00 00
0020 a0 02 fa f0 b7 1b 00 00 02 04 05 b4 04 02 08 0a
0030 9a 68 13 a4 00 00 00 00 01 03 03 07
Can anyone please tell me how to handle this, since I am clueless on this, Is there any command that I can use to make my connect function TCP Handshake handling more attentive to my SYN+ACK packet and finally done with responding only ACK instead of playing plain stupid to send SYN again
As #LuisColorado mentioned to ask how am I generating the packet so the answer is this is how
this is my receiver thread that also transmit response TCP packets like SYN+ACK
void * receiver(void *data)
{
//struct sockaddr_in cliaddr = {0};
int recvlen = -1;
int writelen = -1;
//socklen_t clilen = sizeof(cliaddr);
while (!_do_exit)
{
//recvlen = rrecvfrom(_udp_fd, buf, sizeof(buf), 0, (struct sockaddr*)&cliaddr, &clilen);
char buf[VPN_MAX_MTU] = {0};
char buf_1[VPN_MAX_MTU] = {0};
memset(buf,0,VPN_MAX_MTU);
memset(buf_1,0,VPN_MAX_MTU);
memset(buf,0,VPN_MAX_MTU);
memset(buf_1,0,VPN_MAX_MTU);
char *str_source=malloc(18);
char *str_dest=malloc(18);
memset(str_source,0,18);
memset(str_dest,0,18);
recvlen=read(_tun_fd,buf,VPN_MAX_MTU);
if(recvlen>0)
{
//BUFFER received here
struct iphdr *iph=(struct iphdr *)buf;
struct iphdr *ip=(struct iphdr *)buf_1;
int y=0;
for(int b=0;b<(sizeof(struct iphdr)+sizeof(struct tcphdr));b++)
{
if(y==20)
{
y=0;
//printf("\n");
}
//printf("%x ",buf[b]<<24);
y++;
}
// tcph->check=(tcp_chksum(iph,tcph));
//iph->check = csum(iph, sizeof(*iph));
char str_src[18]={0};
char str_dest_t[18]={0};
//printf("IN %s %s\n",get_ip_str_1(iph->saddr,str_src),get_ip_str_1(iph->daddr,str_dest_t));
memcpy(&ip->daddr,&iph->saddr,sizeof(uint32_t));
memcpy(&ip->saddr,&iph->daddr,sizeof(uint32_t));
//printf("OUT %s %s\n",get_ip_str_1(ip->saddr,str_src),get_ip_str_1(ip->daddr,str_dest_t));
//Create ip
//DOUBLE CHECK FOR BYTE ORDER
//ip->tot_len=iph->tot_len;
populate_ip_some(iph,ip);
ip->tos=0;
ip->tos=iph->tos;
ip->ihl = 5;
ip->version = 4;
ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr));
ip->protocol = 6;
ip->check=0;
//DOUBLE CHECK FOR BYTE ORDER
ip->id=htons(100);
ip->check = htons(csum(ip, sizeof(*ip)));
//printf("before %d \n",htons(iph->check));
iph->check=0;
//printf("middle %d\n",iph->check);
//DOUBLE CHECK FOR BYTE ORDER
iph->check = htons(csum(iph, sizeof(*iph)));
int i=iph->ihl*4;
struct tcphdr *tcph=(struct tcphdr *)(buf+i);
//printf("tcp before %x\n",htons(tcph->check));
tcph->check=0;
printf("TCP START\n");
tcph->check=(tcp_chksum(iph,tcph));
printf("TCP END\n");
//printf("tcp after %d\n",(tcph->check));
//printf("i == %d\n",i);
//POSSIBLY PRINT IPH for fun
//for(int a=0;a<recvlen;a++)
//printf("%x\n",buf[a]);
//GET ihl SEND -- tcp
int j=(ip->ihl*4);
//printf("j == %d\n",j);
int x=0;
//SEEK filling
struct tcphdr *tcp=(struct tcphdr *)(buf_1+20);
//populate_tcp_some(tcph,tcp);//Do LOOK AT THIS FUNCTION TO [SEE/CORRECT IT] >:)
if(tcph->syn==1)
{
printf("WHAT THE HELL THEN WHY\n");
printf("syn\n");
populate_tcp_some(tcph,tcp);
tcp->seq=htonl(1);
// tcp->ack_seq=1;
tcp->syn=1;
tcp->ack=1;
tcp->res1=0;
tcp->res1=0;
tcp->urg=0;
tcp->psh=0;
tcp->fin=0;
tcp->doff=5;
tcp->source=htons(80);
int xx=ntohl(tcph->seq)+1;
printf("\n\nfwdfwdfwd FAWAD %x\n\n",xx);
tcp->ack_seq=htonl(xx);
// printf("received tcp syn = %d\n",tcph->syn);
}
else
{
populate_tcp_some(tcph,tcp);
tcp->syn=0;
tcp->ack=1;
tcp->seq=htonl(1);
tcp->res1=0;
tcp->res1=0;
tcp->urg=0;
tcp->psh=0;
tcp->fin=0;
tcp->doff=5;
tcp->ack_seq=htonl(ntohs(tcph->seq)+1);
// printf("sending tcp syn = %d ack = %d\n",tcp->syn,tcp->ack);
}
printf("syn=%d | ack = %d | fin = %d | %d seq = %d ack_seq = %d | urg = %d | doff = %d | psh = %d rst = %d | rst2 = %d\n",tcp->syn,tcp->ack,tcp->fin,tcp->seq,tcp->ack_seq,tcp->urg,tcp->doff,tcp->psh,tcp->res1,tcp->res2);
//populate_tcp_some(tcph,tcp);
tcp->dest=tcph->source;
tcp->window=htons(40);//tcph->window;
//tcp->ack_seq=tcph->seq;
//printf("%d %d SOURCE PORT \n",ntohs(tcph->source),ntohs(tcp->dest));
tcp->source=htons(80);
printf("%d %d PORTS \n",ntohs(tcp->source),ntohs(tcp->dest));
tcp->check=0;
//TCP CHECKSUM ABOUT TRIPPLE WOW
tcp->check=htons(tcp_chksum(ip,tcp));
//printf("tcpH = %d | tcp = %d\n",tcph->check,htons(tcp->check));
//IF needed make payload data
//WRITE
if (recvlen > 0)
{
writelen = write(_tun_fd, buf_1, sizeof(struct iphdr)+sizeof(struct tcphdr));
//debug("SR:%04d\n", recvlen);
//debug("TW:%04d\n", writelen);
if (writelen < 0)
{
//debug("%s: rwrite() %s [%d]\n", _progname, strerror(errno), errno);
//break;//NO NEED
}
}
else if (recvlen < 0)
{
//debug("%s: rrecvfrom() %s\n", _progname, strerror(errno));
//break;//NO NEED
}
else if (recvlen == 0)
{
//why
}
//FINALLY THEN SEND || DO WIRE SHARK
}
// ...:)__ :) __:) ___:)___ (: __(:__ (;...
}
debug("** Receiver ending.\n");
pthread_exit(NULL);
}
I am writing a C program thats shows instructions using ptrace. This is the code:
#include<stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <string.h>
void run_target()
{
ptrace(PTRACE_TRACEME, 0, 0, 0);
execl("./test", "test", NULL);
}
void debugger(pid_t pid)
{
int status;
wait(&status);
while(WIFSTOPPED(status))
{
struct user_regs_struct regs;
ptrace(PTRACE_GETREGS, pid, 0, ®s);
long instruction = ptrace(PTRACE_PEEKTEXT, pid, regs.rip, 0);
ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
//EDITED SO IT PRINTS ONLY LINES I WANT
if(((regs.rip >> (8*5)) & 0xFF) != 0x7f) //i noticed all the junk lines that shouldnt be there, their regs.rip began with 7f
printf("%llx %16lx\n", regs.rip, instruction);
wait(&status);
}
}
int main()
{
pid_t pid;
pid = fork();
if(pid == 0)
{
run_target();
}
else
{
debugger(pid);
}
return 0;
}
But the output looks like this
...
7f3bf1487308 8348da7426fa8348
7f3bf148730c d47408fa8348da74
7f3bf148730e 8d48d47408fa8348
7f3bf1487312 16ad50d8d48d474
7f3bf14872e8 18c0834810508b48
7f3bf14872ec 48f2014c18c08348
7f3bf14872f0 8948c33948f2014c
7f3bf14872f3 860f118948c33948
7f3bf14872f6 fff670860f118948
7f3bf14872f9 508bfffff670860f
And the objdump -d looks like this:
000000000000064a <main>:
64a: 55 push %rbp
64b: 48 89 e5 mov %rsp,%rbp
64e: 48 8d 3d af 00 00 00 lea 0xaf(%rip),%rdi # 704 <_IO_stdin_used+0x4>
655: b8 00 00 00 00 mov $0x0,%eax
65a: e8 c1 fe ff ff callq 520 <printf#plt>
65f: 48 8d 3d a5 00 00 00 lea 0xa5(%rip),%rdi # 70b <_IO_stdin_used+0xb>
666: b8 00 00 00 00 mov $0x0,%eax
66b: e8 b0 fe ff ff callq 520 <printf#plt>
670: b8 00 00 00 00 mov $0x0,%eax
675: 5d pop %rbp
676: c3 retq
677: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
67e: 00 00
And running ./program | grep "64e" for example shows this
7f46f3bb64e2 89483e8b48f90148
7f46f3bb64e5 8b483989483e8b48
7f46f3bb64e8 48087e8b48398948
7f46f3bb64eb 48c70148087e8b48
7f46f3bb64ef 4808798948c70148
7f46f3bb7318 f64ee8ef894c9174
7f46f3bb731a f64ee8ef894c
7f46f3bb731d 4887eb0000f64ee8
7f46f3800b70 4864e889481f8948
7f46f3800b73 2504334864e88948
55dfb208464e b8000000af3d8d48
7f46f38564e2 89440af883481476
7f46f38f2a11 4334864e8458b48
7f46f380505a e264e8ff894c0874
with this one actually being correct:
55dfb208464e b8000000af3d8d48
So is there something im missing in objdump or is there something missing in my code that it shows more of the rip than it should?
EDIT: added whole code
EDIT: edited the printf, now it prints the lines its supposed to, but it still adds random hex to the beginning
what it should be
64a: 55
what it is
56160a60a64a 9f3d8d48e5894855
I understand why the instruction isnt the same, that is NOT my problem, my problem is why the regs.rip isnt 64a, but is 64a. And the random hex at the start is different everytime i rerun the program.
Your program works, you just have to look at the right place in the right order in your result.
Having that test definition :
#include <stdio.h>
int main()
{
puts("hello");
puts("world");
return 0;
}
objdump -d test produces among other things :
0000000000400526 <main>:
400526: 55 push %rbp
400527: 48 89 e5 mov %rsp,%rbp
40052a: bf d4 05 40 00 mov $0x4005d4,%edi
40052f: e8 cc fe ff ff callq 400400 <puts#plt>
400534: bf da 05 40 00 mov $0x4005da,%edi
400539: e8 c2 fe ff ff callq 400400 <puts#plt>
40053e: b8 00 00 00 00 mov $0x0,%eax
400543: 5d pop %rbp
400544: c3 retq
400545: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40054c: 00 00 00
40054f: 90 nop
if I run your program among the result I found the code with the same addresses of objdump and the same instructions codes, so the init section etc then main (from the line 81208 !) :
400526 4005d4bfe5894855
400527 4005d4bfe58948
40052a fecce8004005d4bf
40052f 5dabffffffecce8
400400 6800200c1225ff
400406 ffe0e90000000068
40040b a25ffffffffe0e9
4003f0 25ff00200c1235ff
4003f6 1f0f00200c1425ff
...
I run on an Intel i7, the instruction bytes have to be read in the reverse order than shown by objdump, for instance the first instruction is 55, then 48 89 e5 then bf d4 05 40 00 then e8 cc fe ff ff etc.
Of course in your case it is like you do 'step' rather than 'next' in a debugger, so on a callq to puts you enter in puts, while objdump disassemble. There are 60084 lines after the address 40052f before to reach address 400534, so 60084 instructions are necessary to do puts("hello"); !
Of course it is possible to print only from the beginning of main, for instance with a lazy way using objdump :
void debugger(pid_t pid)
{
FILE * fp = popen("objdump -d ./test | grep \"<main>:\"", "r");
if (fp == NULL) {
puts("cannot get main address");
}
else {
char line[256];
if (fgets(line, sizeof(line), fp) == NULL) {
puts("no address !");
pclose(fp);
}
else {
unsigned long long main_addr;
pclose(fp);
errno = 0;
main_addr = strtoull(line, NULL, 16);
if (errno != 0)
puts("invalid address");
else {
int found = 0;
int status;
while(wait(&status), WIFSTOPPED(status))
{
struct user_regs_struct regs;
ptrace(PTRACE_GETREGS, pid, 0, ®s);
if (found |= (regs.rip == main_addr)) {
long instruction = ptrace(PTRACE_PEEKTEXT, pid, regs.rip, 0);
printf("%llx %16lx\n", regs.rip, instruction);
}
ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
}
}
}
}
}
[edit from your remark]
ptrace does not know if you want to read a data or instructions, if you want to separate each instructions as objdump you have to know the code of each and the corresponding length, else you can use the difference of addresses from one to the next even that does not work in case of call/jmp/conditional jmp/return :
void debugger(pid_t pid)
{
FILE * fp = popen("objdump -d ./test | grep \"<main>:\"", "r");
if (fp == NULL) {
puts("cannot get main address");
}
else {
char line[256];
if (fgets(line, sizeof(line), fp) == NULL) {
puts("no address !");
pclose(fp);
}
else {
unsigned long long main_addr;
pclose(fp);
errno = 0;
main_addr = strtoull(line, NULL, 16);
if (errno != 0)
puts("invalid address");
else {
int found = 0;
int status;
unsigned long prev_instr;
long long prev_addr = -1;
while(wait(&status), WIFSTOPPED(status))
{
struct user_regs_struct regs;
ptrace(PTRACE_GETREGS, pid, 0, ®s);
if (found |= (regs.rip == main_addr)) {
unsigned long instruction =
(unsigned long) ptrace(PTRACE_PEEKTEXT, pid, regs.rip, 0);
if (prev_addr != -1) {
/* longest instruction has 15 bytes on x86 */
int len = ((regs.rip > prev_addr) && ((regs.rip - prev_addr) <= 15))
? regs.rip - prev_addr : 100;
printf("%llx ", prev_addr);
while (prev_instr && len--) {
printf("%02x ", (unsigned) (prev_instr & 0xff));
prev_instr /= 256;
}
if (len > 15)
puts(" (?)");
else
putchar('\n');
}
prev_instr = instruction;
prev_addr = regs.rip;
}
ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
}
}
}
}
}
now the output is :
400526 55
400527 48 89 e5
40052a bf d4 05 40 00
40052f e8 cc fe ff ff bf da 05 (?)
400400 ff 25 12 0c 20 00
400406 68 00 00 00 00
40040b e9 e0 ff ff ff ff 25 0a (?)
4003f0 ff 35 12 0c 20 00
4003f6 ff 25 14 0c 20 00 0f 1f (?)
7fe20cc1fe10 53
7fe20cc1fe11 48 89 e3
7fe20cc1fe14 48 83 e4 c0
7fe20cc1fe18 48 2b 25 31 df 20 00
7fe20cc1fe1f 48 89 04 24
7fe20cc1fe23 48 89 4c 24 08
...
to do more you have to know the code and length of each instruction call/jmp/conditional jmp/return.Note a code operation can be on 1 or 2 bytes.
I try to create a module for encrypt network packets but when try get data from sk_buff and print it in Hexa not get a correct packet.
I use this method to print data in Hexa :
void pkt_hex_dump(struct sk_buff *skb)
{
size_t len;
int rowsize = 16;
int i, l, linelen, remaining;
int li = 0;
uint8_t *data, ch;
printk("Packet hex dump:\n");
data = (uint8_t *) skb_mac_header(skb);
if (skb_is_nonlinear(skb)) {
len = skb->data_len;
} else {
len = skb->len;
}
remaining = len;
for (i = 0; i < len; i += rowsize) {
printk("%06d\t", li);
linelen = min(remaining, rowsize);
remaining -= rowsize;
for (l = 0; l < linelen; l++) {
ch = data[l];
//data[l] = '1';
printk(KERN_CONT "%02X ", (uint32_t) ch);
}
data += linelen;
li += 10;
printk(KERN_CONT "\n");
}
}
I used this sample to create a chat application.
And output when I send hello world message from client to server is :
[ 3981.963124] Packet hex dump:
[ 3981.963125] 000000 00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00
[ 3981.963128] 000010 00 34 6A 1F 40 00 40 06 D1 A2 7F 00 01 01 7F 00
[ 3981.963130] 000020 00 01 07 E4 BD 36 A2 52 E9 62 6D 40 3D FE 80 10
[ 3981.963133] 000030 02 00 FF 28
And I try to follow this solution but can't get any output.
My hook function
static unsigned int hfunc( void *priv, struct sk_buff *skb, const struct nf_hook_state *state){
struct iphdr *iph; /* IPv4 header */
struct tcphdr *tcph; /* TCP header */
uint16_t sport;
uint16_t dport;
struct ethhdr *ether = eth_hdr(skb);
iph = ip_hdr(skb); /* get IP header */
tcph = tcp_hdr(skb); /* get TCP header */
sport = ntohs(tcph->source);
dport = ntohs(tcph->dest);
/* Watch only port of interest */
if (dport == PTCP_WATCH_PORT || sport == PTCP_WATCH_PORT){
printk(KERN_INFO "UDP packet is received: {'sport': %d; 'dport': %d}\n", sport, dport);
printk("Source: %x:%x:%x:%x:%x:%x\n", ether->h_source[0], ether->h_source[1], ether->h_source[2], ether->h_source[3], ether->h_source[4], ether->h_source[5]);
printk("Destination: %x:%x:%x:%x:%x:%x\n", ether->h_dest[0], ether->h_dest[1], ether->h_dest[2], ether->h_dest[3], ether->h_dest[4], ether->h_dest[5]);
printk("Protocol: %d\n", ether->h_proto);
pkt_hex_dump(skb);
}
return NF_ACCEPT;
}
I have some code that captures audio using the PortAudio library, and then tries to package it into the WAV codec. I then attempt to convert that file to a FLAC file codec, but it keeps telling me it's not a valid .wav file.
wav.h:
#include <stdint.h>
#include <string.h>
/**
* #struct WaveHeader
* #brief A basic WAVE header
*/
typedef struct
{
char RIFF_marker[4];
uint32_t file_size;
char filetype_header[4];
char format_marker[4];
uint32_t data_header_length;
uint16_t format_type;
uint16_t number_of_channels;
uint32_t sample_rate;
uint32_t bytes_per_second;
uint16_t bytes_per_frame;
uint16_t bits_per_sample;
} WaveHeader;
WaveHeader *genericWAVHeader(uint32_t sample_rate, uint16_t bit_depth, uint16_t channels);
WaveHeader *retrieveWAVHeader(const void *ptr);
int writeWAVHeader(FILE* fd, WaveHeader *hdr);
int recordWAV(const char *fileName, WaveHeader *hdr, uint32_t duration);
capture.c:
#include <stdio.h>
#include <stdlib.h>
#include <portaudio.h>
#include <unistd.h>
#include <math.h>
#include "wav.h"
typedef struct
{
int frameIndex; /* Index into sample array. */
int maxFrameIndex;
char* recordedSamples;
} PAData;
WaveHeader *genericWAVHeader(uint32_t sample_rate, uint16_t bit_depth, uint16_t channels)
{
WaveHeader *hdr = malloc(sizeof(*hdr));
if (!hdr) return NULL;
memcpy(&hdr->RIFF_marker, "RIFF", 4);
memcpy(&hdr->filetype_header, "WAVE", 4);
memcpy(&hdr->format_marker, "fmt ", 4);
hdr->data_header_length = 16;
hdr->format_type = 1;
hdr->number_of_channels = channels;
hdr->sample_rate = sample_rate;
hdr->bytes_per_second = sample_rate * channels * bit_depth / 8;
hdr->bytes_per_frame = channels * bit_depth / 8;
hdr->bits_per_sample = bit_depth;
return hdr;
}
int writeWAVHeader(FILE* fd, WaveHeader *hdr)
{
if (!hdr) return -1;
fwrite(&hdr->RIFF_marker, sizeof(*hdr->RIFF_marker), sizeof(&hdr->RIFF_marker), fd);
fwrite(&hdr->file_size, sizeof(hdr->file_size), sizeof(&hdr->file_size), fd);
fwrite(&hdr->filetype_header, sizeof(*hdr->filetype_header), sizeof(&hdr->filetype_header), fd);
fwrite(&hdr->format_marker, sizeof(*hdr->format_marker), sizeof(&hdr->format_marker), fd);
fwrite(&hdr->data_header_length, sizeof(hdr->data_header_length), sizeof(&hdr->data_header_length), fd);
fwrite(&hdr->format_type, sizeof(hdr->format_type), sizeof(&hdr->format_type), fd);
fwrite(&hdr->number_of_channels, sizeof(hdr->number_of_channels), sizeof(&hdr->number_of_channels), fd);
fwrite(&hdr->sample_rate, sizeof(hdr->sample_rate), sizeof(&hdr->sample_rate), fd);
fwrite(&hdr->bytes_per_second, sizeof(hdr->bytes_per_second), sizeof(&hdr->bytes_per_second), fd);
fwrite(&hdr->bytes_per_frame, sizeof(hdr->bytes_per_frame), sizeof(&hdr->bytes_per_frame), fd);
fwrite(&hdr->bits_per_sample, sizeof(hdr->bits_per_sample), sizeof(&hdr->bits_per_sample), fd);
fwrite("data", 1, sizeof("data") - 1, fd);
uint32_t data_size = hdr->file_size - 36;
fwrite(&data_size, sizeof(data_size), sizeof(&data_size), fd);
return 0;
}
static int recordCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
{
PAData *data = (PAData*) userData;
const char *rptr = (const char*) inputBuffer;
char *wptr = &data->recordedSamples[data->frameIndex * 2 /*channels*/];
long framesToCalc;
int finished;
unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
(void) outputBuffer; /* Prevent unused variable warnings. */
(void) timeInfo;
(void) statusFlags;
(void) userData;
if(framesLeft < framesPerBuffer)
{
framesToCalc = framesLeft;
finished = paComplete;
}
else
{
framesToCalc = framesPerBuffer;
finished = paContinue;
}
if(!inputBuffer)
{
for(long i = 0; i < framesToCalc; i++)
{
*wptr++ = 0; /* left */
*wptr++ = 0; /* right */
}
}
else
{
for(long i = 0; i < framesToCalc; i++)
{
*wptr++ = *rptr++; /* left */
*wptr++ = *rptr++; /* right */
}
}
data->frameIndex += framesToCalc;
return finished;
}
int recordWAV(const char *fileName, WaveHeader *hdr, uint32_t duration)
{
PaStreamParameters inputParameters;
PaStream* stream;
PaError err = paNoError;
PAData data;
int totalFrames;
int numSamples;
int numBytes;
char max, val;
double average;
printf("%d", hdr->bytes_per_second);
data.maxFrameIndex = totalFrames = duration * hdr->sample_rate; /* Record for a few seconds. */
data.frameIndex = 0;
numSamples = totalFrames * hdr->number_of_channels;
numBytes = numSamples;
data.recordedSamples = malloc(numBytes);
if(!data.recordedSamples)
{
printf("Could not allocate record array.\n");
goto done;
}
for(int i = 0; i < numSamples; i++) data.recordedSamples[i] = 0;
if((err = Pa_Initialize())) goto done;
inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
if (inputParameters.device == paNoDevice) {
fprintf(stderr,"Error: No default input device.\n");
goto done;
}
inputParameters.channelCount = 2; /* stereo input */
inputParameters.sampleFormat = 1;
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = NULL;
/* Record some audio. -------------------------------------------- */
err = Pa_OpenStream(&stream, &inputParameters, NULL, hdr->sample_rate, paFramesPerBufferUnspecified, paClipOff, recordCallback, &data);
if(err) goto done;
if((err = Pa_StartStream(stream))) goto done;
puts("Now recording!! Please speak into the microphone.");
while((err = Pa_IsStreamActive(stream)) == 1)
{
Pa_Sleep(1000);
printf("index = %d\n", data.frameIndex);
}
if( err < 0 ) goto done;
err = Pa_CloseStream(stream);
if(err) goto done;
/* Measure maximum peak amplitude. */
max = 0;
average = 0.0;
for(int i = 0; i < numSamples; i++)
{
val = data.recordedSamples[i];
val = abs(val);
if( val > max )
{
max = val;
}
average += val;
}
average /= (double)numSamples;
{
FILE* fid = fopen(fileName, "wb");
if(!fid) printf("Could not open file.");
else
{
writeWAVHeader(fid, hdr);
fwrite(data.recordedSamples, hdr->number_of_channels, totalFrames, fid);
fclose(fid);
}
}
done:
Pa_Terminate();
if(data.recordedSamples) /* Sure it is NULL or valid. */
free(data.recordedSamples);
if(err)
{
fprintf(stderr, "An error occured while using the portaudio stream\n");
fprintf(stderr, "Error number: %d\n", err);
fprintf(stderr, "Error message: %s\n", Pa_GetErrorText(err));
err = 1; /* Always return 0 or 1, but no other return codes. */
}
return err;
}
Some tests I ran on the file:
$ xxd -g1 test.wav | head
0000000: 52 49 46 46 00 00 00 30 00 00 00 30 57 41 56 45 RIFF...0...0WAVE
0000010: 66 6d 74 20 10 00 00 00 01 00 02 00 e0 ab 00 00 fmt ............
0000020: 80 af 02 00 04 00 10 00 57 41 56 45 66 6d 74 20 ........WAVEfmt
0000030: 66 6d 74 20 10 00 00 00 10 00 00 00 01 00 02 00 fmt ............
0000040: e0 ab 00 00 80 af 02 00 04 00 10 00 00 00 00 80 ................
0000050: 37 3d 04 10 00 00 03 00 01 00 02 00 e0 ab 00 00 7=..............
0000060: 80 af 02 00 04 00 10 00 02 00 e0 ab 00 00 80 af ................
0000070: 02 00 04 00 10 00 00 00 e0 ab 00 00 80 af 02 00 ................
0000080: 04 00 10 00 00 00 00 80 37 3d 04 10 00 00 03 00 ........7=......
0000090: 00 00 00 00 00 00 00 00 80 af 02 00 04 00 10 00 ................
$ file test.wav
test.wav: RIFF (little-endian) data
$ stat -f %s test.wav
stat: %s: bad format
I'm not quite sure where I am going wrong. Am I not writing out the data correctly?
I don't know about the rest of it, but your fwrites should be like this:
fwrite( hdr->RIFF_marker, sizeof(hdr->RIFF_marker), 1, fd);
fwrite(&hdr->file_size, sizeof(hdr->file_size), 1, fd);
fwrite( hdr->filetype_header, sizeof(hdr->filetype_header), 1, fd);
fwrite( hdr->format_marker, sizeof(hdr->format_marker), 1, fd);
fwrite(&hdr->data_header_length, sizeof(hdr->data_header_length), 1, fd);
fwrite(&hdr->format_type, sizeof(hdr->format_type), 1, fd);
fwrite(&hdr->number_of_channels, sizeof(hdr->number_of_channels), 1, fd);
fwrite(&hdr->sample_rate, sizeof(hdr->sample_rate), 1, fd);
fwrite(&hdr->bytes_per_second, sizeof(hdr->bytes_per_second), 1, fd);
fwrite(&hdr->bytes_per_frame, sizeof(hdr->bytes_per_frame), 1, fd);
fwrite(&hdr->bits_per_sample, sizeof(hdr->bits_per_sample), 1, fd);
fwrite("data", 4, 1, fd);