Shell Script: Hexadecimal Loop - linux

I am trying to learn shell script and writing a simple script to increment Hex values in the loop.
Here is my script:
increment=0x0001
handle=0x0001
for((i=1;i<=20;i++))
do
echo $handle
handle=$(($handle + $increment))
handle=$(printf '%x' $handle)
done
Here is my output:
0x0001
2
3
4
5
6
7
8
9
a
1
2
3
4
5
6
7
8
9
a
It is working fine till 10th iteration but after that it is starting from 1 again.
Can any one let me know my mistake?
EDIT: After removing handle=$(printf '%x' $handle) line output is:
0x0001
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Actually I want output in HEX only.

It has to do with how you print the value try printf '%#x' or printf '%#X'
Just change the line you are using to print the content with a leading 0x as:-
handle=$(printf '%#x' $handle)
(or) to have leading hex-character as 0X
handle=$(printf '%#X' $handle)
With the changes, you get the output as below:-
$ ./script.sh
0x0001
0x2
0x3
0x4
0x5
0x6
0x7
0x8
0x9
0xa
0xb
0xc
0xd
0xe
0xf
0x10
0x11
0x12
0x13
0x14
0x15
0x16
0x17
0x18
0x19
0x1a
0x1b
0x1c
0x1d
0x1e
0x1f
0x20
For more formatting options check here:- http://wiki.bash-hackers.org/commands/builtin/printf (and) http://ss64.com/bash/printf.html

Related

How to print in reverse in assembly language using DOSBox Debug?

This is one of the examples my instructor gave me but I need to find a way to reverse the order of what I input.
Here's the code:
e200 "Name: $"
e300 "Hello, $"
a100
mov ah, 09
mov dx, 200
int 21
mov bx, 400
mov ah, 01
int 21
mov [bx], al
inc bx
cmp bx, 405
jne 10a
mov cl, 24
mov [bx], cl
mov ah, 02
mov dl, 0a
int 21
mov dl, 0d
int 21
mov ah, 09
mov dx, 300
int 21
mov ah, 09
mov dx, 400
int 21
int 20
Output is:
Name: Maria
Hello, Maria
Expected Output (reverse):
Name: Maria
Hello, ariaM
Tested on current lDebug and (creating the executable only) on Microsoft's Debug from MS-DOS version 2 (available under MIT license). This should solve your task.
f 100 4FF 90
a 100
mov ah, 09
mov dx, 500
int 21
mov ah, 0A
mov dx, 800
int 21
mov ah, 09
mov dx, 600
int 21
xor cx, cx
mov cl, [801]
mov bx, cx
add bx, 801
jcxz 190
a 130
mov ah, 02
mov dl, [bx]
int 21
dec bx
loop 130
a 190
mov ah, 09
mov dx, 700
int 21
mov ax, 4C00
int 21
e 800 FF 0 0D
e 500 "Name: $"
e 600 0D 0A "Hello, $"
e 700 0D 0A "$"
g
q
800 up to below 901 holds a maximum size buffer for interrupt 21h service 0Ah, which we initialise to FF (buffer size 255), 0 (nothing to recall), 0D (indicate end of recallable input).
500, 600, and 700 contain dollar-terminated messages to be used with interrupt 21h service 09h.
The output loop counter is initialised to CX = CL = length in bytes of input line, as returned by service 0Ah, excluding the final Carriage Return.
The offset to output is initialised to BX = 801 + CX, which is the same as 802 + CX - 1. 802 is the address of the first byte of the returned input. 802 + CX is the address behind the last byte of the returned input. The minus one serves as an adjustment to point at the last byte instead of behind it.
jcxz skips the loop for empty names.
mov dl, [bx] loads a byte into the low half of DX.
Interrupt 21h service 02h is used to output a byte.
dec bx decrements the offset stored in BX.
The loop 130 instruction decrements CX and jumps back if the resulting CX is non-zero.
The f command is to fill a part of the code segment with all nop instructions. Along with the different a commands this allows us to place and use fixed offsets for jump targets in the code, without having to know exactly how long each instruction will be.
Enter the name input, then indicate its end using the Enter key.
To generate an executable, prepend the command f 100 9FF 0, then instead of the g command run this:
r bx
0
r cx
900
n test.com
w 100
q

Sockets programming: DIG DNS Query Messages: Incorrect header length?

RFC Reference
I am working on a project which involves sockets programming and interpreting the output from DIG DNS queries.
I'm using RFC 1035 as my reference. Although this is quite old now (1987) as far as I can tell from later RFCs (for example 8490) the DNS headers are still the same.
https://www.rfc-editor.org/rfc/rfc1035
Code Overview: IPv6 TCP query
I have written a short program in C which reads from a IPv6 TCP socket. I send data to this socket using DIG. (My program simply reads all data it sees on a socket, and prints it to stdout.)
Note that there are two unusual things here:
Firstly the use of IPv6
Secondly the use of TCP (DNS messages are often UDP)
Here is the command used:
dig #::1 -p 8053 duckduckgo.com +tcp
I am running dig version DiG 9.16.13-Debian, on Debian Testing. (cera 2021-May)
Output, Discussion and Question
Here is the hexadecimal and printable character output which is read from the socket:
Hex:
00 37 61 78 01 20 00 01 00 00 00 00 00 01 0A 64 75 63 6B 64 75 63 6B 67 6F 03 63 6F 6D 00 00 01 00 01 00 00 29 10 00 00 00 00 00 00 0C 00 0A 00 08 00 7A 4* 48 2C 16 0* 33
Char:
00 7 61 x 01 20 00 01 00 00 00 00 00 01 0A d u c k d u c k g o 03 c o m 00 00 01 00 01 00 00 ) 10 00 00 00 00 00 00 0C 00 0A 00 08 00 z 4* H , 16 0* 33
If non-printable characters are encountered, the hex value is printed instead.
Although this is a fairly long stream of data, the question relates to the length of the header.
According to RFC 1035, the length of the header should be 12 bytes.
4.1.1. Header section format
The header contains the following fields:
1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
The header is followed by a QUESTION SECTION. The question section begins with a single byte which specifies the length.
Inspecting the data stream above, we see that the byte at offset 12 has a value of 0. I repeat it below with offset numbers to make it clear. The data is in the middle row, the row above and below are byte offsets.
0 1 2 3 4 5 6 7 8 9 10 11 <- byte 12
00 37 61 78 01 20 00 01 00 00 00 00 00 01 0A 64 75 63 6B ...
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <- byte 15
This clearly doesn't make any sense.
Looking again at the stream, we can see that "duckduckgo" is preceeded by the byte 0A. This is 10 in decimal and corresponds to the 10 characters of "duckduckgo". This string is followed by a byte 03 which corresponds to the 3 bytes of "com".
The offset of the byte 0A is 15. Not 12.
I must have misunderstood the RFC specification. But what have I misunderstood? Does the header itself start at a different offset to what I think it is? (Byte zero.) Or is there perhaps some padding between the end of the header and the beginning of the first question section?
Existing Question on this site:
Comments: The below link states that there is no padding. This is the only answer on this question. The question is about DNS responses rather than queries, and does not ask about the header section of a query. (Although information from one should presumably apply to the other, but possibly does not.)
Do DNS messages pad names to an even number of bytes?
Comments: The below link asks about the best way to build a data structure to handle DNS data. Additionally, the answer notes that one has to be careful about network byte order and machine byte order. I am already aware of this and I use ntohs() to convert from network byte order to x86_64 byte order before printing information to stdout. This is not the problem and does not explain why I see information about the dns query starting at byte 15 instead of 12, when the header should be a fixed size of 12 bytes.
Implementing a DNS Query in c++ according to RFC 1035
Thanks to #SteffenUllrich who prompted the solution for this in the comments.
RFC 1035 4.2.2 states
4.2.2. TCP usage
Messages sent over TCP connections use server port 53 (decimal). The
message is prefixed with a two byte length field which gives the message
Mockapetris [Page 32]
RFC 1035 Domain Implementation and Specification November 1987
length, excluding the two byte length field. This length field allows
the low-level processing to assemble a complete message before beginning
to parse it.
I had removed the 2-byte field at the start of my struct at some point.
This is what the structure looks like with the 2 byte length field re-enabled.
struct __attribute__((__packed__)) dns_header
{
unsigned short ID;
union
{
unsigned short FLAGS;
struct
{
unsigned short QR : 1;
unsigned short OPCODE : 4;
unsigned short AA : 1;
unsigned short TC : 1;
unsigned short RD : 1;
unsigned short RA : 1;
unsigned short Z : 3;
unsigned short RCODE : 4;
};
};
unsigned short QDCOUNT;
unsigned short ANCOUNT;
unsigned short NSCOUNT;
unsigned short ARCOUNT;
};
struct __attribute__((__packed__)) dns_struct_tcp
{
unsigned short length; // length excluding 2 bytes for length field
struct dns_header header;
};
For example: I recieved a TCP packet of length 53 bytes. The value of length is set to 51.
To read data into this struct:
memcpy(&dnsdata, buf, sizeof(struct dns_struct_tcp));
To interpret this data (since it is stored in network byte order):
void dns_header_print(FILE *file, const struct dns_header *header)
{
fprintf(file, "ID: %u\n", ntohs(header->ID));
char str_FLAGS[8 * sizeof(unsigned short) + 1];
str_FLAGS[8 * sizeof(unsigned short)] = '\0';
print_binary_16_fixed_width(str_FLAGS, header->FLAGS);
fprintf(file, "FLAGS: %s\n", str_FLAGS);
fprintf(file, "FLAGS: QOP ATRRZZZR \n");
fprintf(file, " RCODEACDA CODE\n");
fprintf(file, "QDCOUNT: %u\n", ntohs(header->QDCOUNT));
fprintf(file, "ANCOUNT: %u\n", ntohs(header->ANCOUNT));
fprintf(file, "NSCOUNT: %u\n", ntohs(header->NSCOUNT));
fprintf(file, "ARCOUNT: %u\n", ntohs(header->ARCOUNT));
}
Note that the flags are unchanged, since each field of flags is less than 8 bits in length. However on x86_64 systems, unsigned short is stored in little-endian format, hence ntohs() is use to convert data which is in big-endian (network) byte order to little-endian (host) byte order.

Command to convert Hex to decimal in Linux? [duplicate]

This question already has answers here:
Hexadecimal To Decimal in Shell Script
(8 answers)
Closed 2 years ago.
I'm trying to convert the hexadecimal value to a decimal value in my map file. For example, here is a snippet of the file
.bss 0xc g2.comms
.bss 0xc g2.comms
.bss 0xa g2.comms
.bss 0x14 g2.comms
.rodata 0x64 g2.comms
.rodata 0x1ac g2.comms
.rodata 0x270 g2.comms
.rodata 0x18 g2.comms
Is there a one line command that can convert the 2nd column from hexadecimal to decimal?
If you have GNU awk (gawk):
$ awk -n '{print $2+0}' file
12
12
10
20
100
428
624
24
-n (or --non-decimal-data) causes "the automatic interpretation of octal and hexadecimal values in input data." In order to make sure that awk treats the second column as a number, not a string, we add zero to it: $2+0.

Trying to get the average of 3 2-digit numbers NASM x86

I've seen other similar questions and I've tried the solutions mentioned but my code simply doesn't work. It gets three 2-digit numbers and adds it, divides by 3 to get the floored average, and prints it. Originally it works with the sum of numbers < 255, now I'm trying to make it work for cases > 255. With this code I'm getting Floating point exception (core dumped) in the terminal, and I'm at a loss why.
; i have successfully scanned, converted and joined the 3 numbers as n1o, n2o, n3o
; add to al, then ax
mov ax, 0
add al, [n1o]
add al, [n2o]
add ax, [n3o] ; to prevent loss of sum > 255
; will this work?
; average
mov bl, 3
div bl ; divide ax by 3
; split
mov ah, 0 ; clear remainder of average
mov bl, 10
div bl
; assign to a1
mov [a1t], al
mov [a1o], ah
; convert a1
; print a1
; terminate
EDIT: my declarations
; n1
n1t resb 1
n1o resb 1
; n2
n2t resb 1
n2o resb 1
; n3
n3t resb 1
n3o resb 1
; a1
a1t resb 1
a1o resb 1
; reflects the average
; s1
s1w resw 1
; sum of n1 n2 n3

Trying to Understand the size of a binary file (NASM) output

I have these two files myboot.asm and theirboot.asm (listed respectively):
;----------------------------------------------------------------------
; A Simple boot program that prints the string 'Hello World'
; Author: Matthew Hoggan 2012
;----------------------------------------------------------------------
Output db 'Hello',0x00 ; Output string for bios
org 0x7c00 ; This is where BIOS loads the bootloader
entry: ; Label to Signify entry to program
jmp short begin ; Jump over the DOS boot record data
; --------------------------------------------
; Boot program code begins here
; --------------------------------------------
begin: ; Label to Signify entry to program
mov si, Output ; Get pointer to string
loop: ; Top of loop to iterate over string
mov al, [si] ; Move contents of pointer to al
or al, al ; Check if character pointed to is Zero
jz hang ; Zero signifies end of string
call print_char ; Print current char in al
jmp loop ; Repeat
; --------------------------------------------
; Function to print char
; assume caller has placed char in al
; --------------------------------------------
print_char:
mov ah, 0x0e ; Function to print a character to the screen
mov bl, 7 ; color/style to use for the character
int 0x10 ; print the character
hang:
jmp hang ; just loop forever.
;---------------------------------------------
; Write Zeros up to end of program - 2 then boot signature
;---------------------------------------------
size equ $ - entry
times (512 - size - 2) db 0
db 0x55, 0xAA ;2 byte boot signature
;----------------------------------------------------------------------
; A Simple boot program that prints the string 'Hello World'
;----------------------------------------------------------------------
org 0x7c00 ; This is where BIOS loads the bootloader
entry: ; Label to Signify entry to program
jmp short begin ; Jump over the DOS boot record data
; --------------------------------------------
; Boot program code begins here
; --------------------------------------------
begin: ; Label to Signify entry to program
xor ax, ax ; Zero out ax
mov ds, ax ; Set data segment to base of RAM
mov si, msg ; Get pointer to string
call putstr ; Print the message
jmp hang ; Go to infinite loop
msg db 'Hello, World',0x00
putstr: ; Function to print the string
lodsb ; al = [DS:SI]
or al, al ; Set zero flag if al = 0
jz ret ; Jump to end of function if al = 0
mov ah, 0x0e ; Video function 0Eh (print char)
mov bx, 0x0007 ; Color
int 0x10
jmp putstr
ret:
retn
hang:
jmp hang ; just loop forever.
;---------------------------------------------
; Write Zeros up to end of program - 2 then boot signature
;---------------------------------------------
size equ $ - entry
times (512 - size - 2) db 0
db 0x55, 0xAA ;2 byte boot signature
Building both of these files running hexdump on them and listing the files in the directory to see their size reveals:
mehoggan#mehoggan-laptop:~/Code/play/asm$ nasm myboot.asm -f bin -o boot.bin && hexdump boot.bin && ls -l && echo "------" && nasm bootloader1.asm -f bin -o boot.bin && hexdump boot.bin && ls -l
0000000 6548 6c6c 006f 00eb 00be 8a7c 0804 74c0
0000010 e80c 0003 f4e9 b4ff b30e cd07 e910 fffd
0000020 0000 0000 0000 0000 0000 0000 0000 0000
*
0000200 0000 0000 aa55
0000206
total 20
-rw-r--r-- 1 mehoggan mehoggan 518 2012-02-29 21:57 boot.bin
-rw-r--r-- 1 mehoggan mehoggan 2290 2012-02-29 20:23 bootloader0.asm
-rw-r--r-- 1 mehoggan mehoggan 1661 2012-02-29 21:55 bootloader1.asm
-rw-r--r-- 1 mehoggan mehoggan 1786 2012-02-29 21:49 myboot.asm
-rw-r--r-- 1 mehoggan mehoggan 1065 2012-02-29 20:14 ourbootloader.asm
------
0000000 00eb c031 d88e 0fbe e87c 0010 1de9 4800
0000010 6c65 6f6c 202c 6f57 6c72 0064 08ac 74c0
0000020 b40a bb0e 0007 10cd f1e9 c3ff fde9 00ff
0000030 0000 0000 0000 0000 0000 0000 0000 0000
*
00001f0 0000 0000 0000 0000 0000 0000 0000 aa55
0000200
total 20
-rw-r--r-- 1 mehoggan mehoggan 512 2012-02-29 21:57 boot.bin
-rw-r--r-- 1 mehoggan mehoggan 2290 2012-02-29 20:23 bootloader0.asm
-rw-r--r-- 1 mehoggan mehoggan 1661 2012-02-29 21:55 bootloader1.asm
-rw-r--r-- 1 mehoggan mehoggan 1786 2012-02-29 21:49 myboot.asm
-rw-r--r-- 1 mehoggan mehoggan 1065 2012-02-29 20:14 ourbootloader.asm
Why are the files sizes off by 6 bytes?
Check out the last little block of assembly code there:
size equ $ - entry
times (512 - size - 2) db 0
db 0x55, 0xAA ;2 byte boot signature
This block of code calculates how big the code is (from entry to the current location), then pads it out to a total of 512 bytes with zeroes and a signature 0x55 0xAA in the last two positions. That is:
entry: Some code
.
.
.
Some zeroes
.
.
.
0x55 0xAA
That little assembly block means the output size from the entry label to 0x55 0xAA is always 512 bytes. In your first example, there is a six byte string Hello\0 before entry. In your second example there's not. Therefore, the first program is six bytes longer than the second. You probably want to move that string to someplace after entry and before the padding block.
If you use hexump -C on your binaries, you'll see the string right up at the top of the first binary.

Resources