Specifically to resolve the question of binding variables to specific addresses in flash memory on the PIC18 with the C18 compiler, please reference the section "Pragmas" in the hlpC18ug.chm in the doc directory where the compiler is installed.
To do this you need to define a new "section" in memory and bind it to a start address so
#pragma romdata serial_no_section=0x1700
This creates a new section called "serial_no_section" that starts at address 0x1700 in flash (program) memory (because we defined "romdata" in the #pragma).
Directly after the #pragma line, define your variable(s) so:
#pragma romdata serial_no_section=0x1700
const rom int mySerialNumber = 0x1234;
#pragma romdata
Now you have 0x12 at address 0x1700 and 0x34 at address 0x1701 in memory (because PIC18 uses the little-endian model). The "const rom" ensure that the compiler knows that this is a const variable type, and that the variable lies in "rom" memory and thus need to be accessed via table read instructions.
The final #pragma romdata
statement ensures that any following variable declarations are linked to default memory sections as the linker sees fits rather than following on in the "serial_no_section" section.
Now all code can simply reference the variable "mySerialNumber", and you know exactly what address the serial number can be found at in memory.
Editing the HEX code can be a bit challenging as you need to calculate the checksum for each line you edit. I am working on a C++ class to decode and encode Intel HEX files which should make this easier, but it is not finished yet. Decoding files works, encoding again is not yet implemented. The project (if you are interested) is here https://github.com/codinghead/Intel-HEX-Class
Hope this helps
There are two ways of programming an AVR device.
The first is via an external programmer that interfaces with "hidden" hardware on the chip. The most common form of this is ISP, described in AVR910. Other methods exist, see the datasheet of the relevant AVR device for details.
The other is self-programming, which involves code running on the AVR device to accept the data to be programmed through one or more pins on the chip and then using special opcodes to write the data to flash and EEPROM. This is described in AVR109.
Note that "programming by USB" is actually self-programming where the bootloader opens a serial connection and the programming software sends the data through this serial connection. This is true both on devices with a separate USB interface chip such as the Arduino Uno as well as devices with integrated USB support such as the Arduino Leonardo.
Best Answer
Winavr has not been updated since 2010; the ATtiny402 was released in 2018. According to en.wikipedia.org/wiki/ATtiny_microcontroller_comparison_chart the ATtiny402 requires gcc arch id avrxmega3. So winavr will not be able to work. Check whether you have a new enough version of gcc to support ATtiny402 (avrxmega3), the version installed with winavr is probably out of date.