2003-12-11 22:38:14 +00:00
|
|
|
/*
|
2004-01-02 04:31:06 +00:00
|
|
|
* Copyright (c) 2003
|
|
|
|
* Bill Paul <wpaul@windriver.com>. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by Bill Paul.
|
|
|
|
* 4. Neither the name of the author nor the names of any co-contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
|
|
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
2003-12-11 22:38:14 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#include <sys/queue.h>
|
|
|
|
|
|
|
|
#include "inf.h"
|
|
|
|
|
|
|
|
extern FILE *yyin;
|
|
|
|
int yyparse (void);
|
|
|
|
|
|
|
|
const char *words[W_MAX]; /* More than we'll need. */
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
static struct section_head sh;
|
|
|
|
static struct reg_head rh;
|
|
|
|
static struct assign_head ah;
|
|
|
|
|
|
|
|
static char *sstrdup (const char *);
|
|
|
|
static struct assign
|
|
|
|
*find_assign (const char *, const char *);
|
|
|
|
static struct section
|
|
|
|
*find_section (const char *);
|
2004-03-07 02:49:06 +00:00
|
|
|
static void dump_deviceids_pci (void);
|
|
|
|
static void dump_deviceids_pcmcia (void);
|
2003-12-11 22:38:14 +00:00
|
|
|
static void dump_pci_id (const char *);
|
2004-03-07 02:49:06 +00:00
|
|
|
static void dump_pcmcia_id (const char *);
|
2005-02-16 18:37:14 +00:00
|
|
|
static void dump_regvals (void);
|
2003-12-18 03:51:21 +00:00
|
|
|
static void dump_paramreg (const struct section *,
|
|
|
|
const struct reg *, int);
|
2003-12-11 22:38:14 +00:00
|
|
|
|
|
|
|
static FILE *ofp;
|
|
|
|
|
|
|
|
int
|
|
|
|
inf_parse (FILE *fp, FILE *outfp)
|
|
|
|
{
|
|
|
|
TAILQ_INIT(&sh);
|
|
|
|
TAILQ_INIT(&rh);
|
|
|
|
TAILQ_INIT(&ah);
|
|
|
|
|
|
|
|
ofp = outfp;
|
|
|
|
yyin = fp;
|
|
|
|
yyparse();
|
|
|
|
|
2004-03-07 02:49:06 +00:00
|
|
|
dump_deviceids_pci();
|
|
|
|
dump_deviceids_pcmcia();
|
|
|
|
fprintf(outfp, "#ifdef NDIS_REGVALS\n");
|
2003-12-11 22:38:14 +00:00
|
|
|
dump_regvals();
|
2004-03-07 02:49:06 +00:00
|
|
|
fprintf(outfp, "#endif /* NDIS_REGVALS */\n");
|
2003-12-11 22:38:14 +00:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
section_add (const char *s)
|
|
|
|
{
|
|
|
|
struct section *sec;
|
|
|
|
|
|
|
|
sec = malloc(sizeof(struct section));
|
|
|
|
bzero(sec, sizeof(struct section));
|
|
|
|
sec->name = s;
|
|
|
|
TAILQ_INSERT_TAIL(&sh, sec, link);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct assign *
|
|
|
|
find_assign (const char *s, const char *k)
|
|
|
|
{
|
|
|
|
struct assign *assign;
|
|
|
|
char newkey[256];
|
|
|
|
|
|
|
|
/* Deal with string section lookups. */
|
|
|
|
|
|
|
|
if (k != NULL && k[0] == '%') {
|
|
|
|
bzero(newkey, sizeof(newkey));
|
|
|
|
strncpy(newkey, k + 1, strlen(k) - 2);
|
|
|
|
k = newkey;
|
|
|
|
}
|
|
|
|
|
|
|
|
TAILQ_FOREACH(assign, &ah, link) {
|
|
|
|
if (strcasecmp(assign->section->name, s) == 0) {
|
|
|
|
if (k == NULL)
|
|
|
|
return(assign);
|
|
|
|
else
|
|
|
|
if (strcasecmp(assign->key, k) == 0)
|
|
|
|
return(assign);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
stringcvt(const char *s)
|
|
|
|
{
|
|
|
|
struct assign *manf;
|
|
|
|
|
|
|
|
manf = find_assign("strings", s);
|
|
|
|
if (manf == NULL)
|
|
|
|
return(s);
|
|
|
|
return(manf->vals[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct section *
|
|
|
|
find_section (const char *s)
|
|
|
|
{
|
|
|
|
struct section *section;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(section, &sh, link) {
|
|
|
|
if (strcasecmp(section->name, s) == 0)
|
|
|
|
return(section);
|
|
|
|
}
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
2004-03-07 02:49:06 +00:00
|
|
|
static void
|
|
|
|
dump_pcmcia_id(const char *s)
|
|
|
|
{
|
|
|
|
char *manstr, *devstr;
|
|
|
|
char *p0, *p;
|
|
|
|
|
|
|
|
p0 = __DECONST(char *, s);
|
|
|
|
|
|
|
|
p = strchr(p0, '\\');
|
|
|
|
if (p == NULL)
|
|
|
|
return;
|
|
|
|
p0 = p + 1;
|
|
|
|
|
|
|
|
p = strchr(p0, '-');
|
|
|
|
if (p == NULL)
|
|
|
|
return;
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
manstr = p0;
|
|
|
|
|
|
|
|
/* Convert any underscores to spaces. */
|
|
|
|
|
|
|
|
while (*p0 != '\0') {
|
|
|
|
if (*p0 == '_')
|
|
|
|
*p0 = ' ';
|
|
|
|
p0++;
|
|
|
|
}
|
|
|
|
|
|
|
|
p0 = p + 1;
|
|
|
|
p = strchr(p0, '-');
|
|
|
|
if (p == NULL)
|
|
|
|
return;
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
devstr = p0;
|
|
|
|
|
|
|
|
/* Convert any underscores to spaces. */
|
|
|
|
|
|
|
|
while (*p0 != '\0') {
|
|
|
|
if (*p0 == '_')
|
|
|
|
*p0 = ' ';
|
|
|
|
p0++;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(ofp, "\t\\\n\t{ \"%s\", \"%s\", ", manstr, devstr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-12-11 22:38:14 +00:00
|
|
|
static void
|
|
|
|
dump_pci_id(const char *s)
|
|
|
|
{
|
|
|
|
char *p;
|
2003-12-18 03:51:21 +00:00
|
|
|
char vidstr[7], didstr[7], subsysstr[14];
|
2003-12-11 22:38:14 +00:00
|
|
|
|
|
|
|
p = strcasestr(s, "VEN_");
|
|
|
|
if (p == NULL)
|
|
|
|
return;
|
|
|
|
p += 4;
|
|
|
|
strcpy(vidstr, "0x");
|
|
|
|
strncat(vidstr, p, 4);
|
|
|
|
p = strcasestr(s, "DEV_");
|
|
|
|
if (p == NULL)
|
|
|
|
return;
|
|
|
|
p += 4;
|
|
|
|
strcpy(didstr, "0x");
|
|
|
|
strncat(didstr, p, 4);
|
|
|
|
if (p == NULL)
|
|
|
|
return;
|
2003-12-18 03:51:21 +00:00
|
|
|
p = strcasestr(s, "SUBSYS_");
|
|
|
|
if (p == NULL)
|
|
|
|
strcpy(subsysstr, "0x00000000");
|
|
|
|
else {
|
|
|
|
p += 7;
|
|
|
|
strcpy(subsysstr, "0x");
|
|
|
|
strncat(subsysstr, p, 8);
|
|
|
|
}
|
2003-12-11 22:38:14 +00:00
|
|
|
|
2003-12-18 03:51:21 +00:00
|
|
|
fprintf(ofp, "\t\\\n\t{ %s, %s, %s, ", vidstr, didstr, subsysstr);
|
2003-12-11 22:38:14 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2004-03-07 02:49:06 +00:00
|
|
|
dump_deviceids_pci()
|
2003-12-11 22:38:14 +00:00
|
|
|
{
|
|
|
|
struct assign *manf, *dev;
|
|
|
|
struct section *sec;
|
|
|
|
struct assign *assign;
|
2003-12-12 03:40:05 +00:00
|
|
|
char xpsec[256];
|
2004-01-27 09:05:52 +00:00
|
|
|
int found = 0;
|
2003-12-11 22:38:14 +00:00
|
|
|
|
|
|
|
/* Find manufacturer name */
|
|
|
|
manf = find_assign("Manufacturer", NULL);
|
|
|
|
|
|
|
|
/* Find manufacturer section */
|
2003-12-12 03:40:05 +00:00
|
|
|
if (manf->vals[1] != NULL &&
|
2003-12-13 08:48:35 +00:00
|
|
|
(strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
|
2004-01-03 02:25:21 +00:00
|
|
|
strcasecmp(manf->vals[1], "NTx86") == 0 ||
|
Add support for Windows/x86-64 binaries to Project Evil.
Ville-Pertti Keinonen (will at exomi dot comohmygodnospampleasekthx)
deserves a big thanks for submitting initial patches to make it
work. I have mangled his contributions appropriately.
The main gotcha with Windows/x86-64 is that Microsoft uses a different
calling convention than everyone else. The standard ABI requires using
6 registers for argument passing, with other arguments on the stack.
Microsoft uses only 4 registers, and requires the caller to leave room
on the stack for the register arguments incase the callee needs to
spill them. Unlike x86, where Microsoft uses a mix of _cdecl, _stdcall
and _fastcall, all routines on Windows/x86-64 uses the same convention.
This unfortunately means that all the functions we export to the
driver require an intermediate translation wrapper. Similarly, we have
to wrap all calls back into the driver binary itself.
The original patches provided macros to wrap every single routine at
compile time, providing a secondary jump table with a customized
wrapper for each exported routine. I decided to use a different approach:
the call wrapper for each function is created from a template at
runtime, and the routine to jump to is patched into the wrapper as
it is created. The subr_pe module has been modified to patch in the
wrapped function instead of the original. (On x86, the wrapping
routine is a no-op.)
There are some minor API differences that had to be accounted for:
- KeAcquireSpinLock() is a real function on amd64, not a macro wrapper
around KfAcquireSpinLock()
- NdisFreeBuffer() is actually IoFreeMdl(). I had to change the whole
NDIS_BUFFER API a bit to accomodate this.
Bugs fixed along the way:
- IoAllocateMdl() always returned NULL
- kern_windrv.c:windrv_unload() wasn't releasing private driver object
extensions correctly (found thanks to memguard)
This has only been tested with the driver for the Broadcom 802.11g
chipset, which was the only Windows/x86-64 driver I could find.
2005-02-16 05:41:18 +00:00
|
|
|
strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
|
|
|
|
strcasecmp(manf->vals[1], "NTamd64") == 0)) {
|
2003-12-12 03:40:05 +00:00
|
|
|
/* Handle Windows XP INF files. */
|
|
|
|
snprintf(xpsec, sizeof(xpsec), "%s.%s",
|
|
|
|
manf->vals[0], manf->vals[1]);
|
|
|
|
sec = find_section(xpsec);
|
|
|
|
} else
|
|
|
|
sec = find_section(manf->vals[0]);
|
2003-12-11 22:38:14 +00:00
|
|
|
|
2004-03-07 02:49:06 +00:00
|
|
|
/* See if there are any PCI device definitions. */
|
|
|
|
|
|
|
|
TAILQ_FOREACH(assign, &ah, link) {
|
|
|
|
if (assign->section == sec) {
|
|
|
|
dev = find_assign("strings", assign->key);
|
|
|
|
if (strcasestr(assign->vals[1], "PCI") != NULL) {
|
|
|
|
found++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
found = 0;
|
|
|
|
|
|
|
|
/* Emit start of PCI device table */
|
|
|
|
fprintf (ofp, "#define NDIS_PCI_DEV_TABLE");
|
2003-12-11 22:38:14 +00:00
|
|
|
|
2004-01-27 09:05:52 +00:00
|
|
|
retry:
|
|
|
|
|
2003-12-11 22:38:14 +00:00
|
|
|
/*
|
|
|
|
* Now run through all the device names listed
|
|
|
|
* in the manufacturer section and dump out the
|
|
|
|
* device descriptions and vendor/device IDs.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TAILQ_FOREACH(assign, &ah, link) {
|
|
|
|
if (assign->section == sec) {
|
|
|
|
dev = find_assign("strings", assign->key);
|
|
|
|
/* Emit device IDs. */
|
|
|
|
if (strcasestr(assign->vals[1], "PCI") != NULL)
|
|
|
|
dump_pci_id(assign->vals[1]);
|
2004-03-07 02:49:06 +00:00
|
|
|
else
|
2004-01-23 22:28:22 +00:00
|
|
|
continue;
|
2004-03-07 02:49:06 +00:00
|
|
|
/* Emit device description */
|
|
|
|
fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
|
|
|
|
found++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Someone tried to fool us. Shame on them. */
|
|
|
|
if (!found) {
|
|
|
|
found++;
|
|
|
|
sec = find_section(manf->vals[0]);
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Emit end of table */
|
|
|
|
|
|
|
|
fprintf(ofp, "\n\n");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dump_deviceids_pcmcia()
|
|
|
|
{
|
|
|
|
struct assign *manf, *dev;
|
|
|
|
struct section *sec;
|
|
|
|
struct assign *assign;
|
|
|
|
char xpsec[256];
|
|
|
|
int found = 0;
|
|
|
|
|
|
|
|
/* Find manufacturer name */
|
|
|
|
manf = find_assign("Manufacturer", NULL);
|
|
|
|
|
|
|
|
/* Find manufacturer section */
|
|
|
|
if (manf->vals[1] != NULL &&
|
|
|
|
(strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
|
|
|
|
strcasecmp(manf->vals[1], "NTx86") == 0 ||
|
Add support for Windows/x86-64 binaries to Project Evil.
Ville-Pertti Keinonen (will at exomi dot comohmygodnospampleasekthx)
deserves a big thanks for submitting initial patches to make it
work. I have mangled his contributions appropriately.
The main gotcha with Windows/x86-64 is that Microsoft uses a different
calling convention than everyone else. The standard ABI requires using
6 registers for argument passing, with other arguments on the stack.
Microsoft uses only 4 registers, and requires the caller to leave room
on the stack for the register arguments incase the callee needs to
spill them. Unlike x86, where Microsoft uses a mix of _cdecl, _stdcall
and _fastcall, all routines on Windows/x86-64 uses the same convention.
This unfortunately means that all the functions we export to the
driver require an intermediate translation wrapper. Similarly, we have
to wrap all calls back into the driver binary itself.
The original patches provided macros to wrap every single routine at
compile time, providing a secondary jump table with a customized
wrapper for each exported routine. I decided to use a different approach:
the call wrapper for each function is created from a template at
runtime, and the routine to jump to is patched into the wrapper as
it is created. The subr_pe module has been modified to patch in the
wrapped function instead of the original. (On x86, the wrapping
routine is a no-op.)
There are some minor API differences that had to be accounted for:
- KeAcquireSpinLock() is a real function on amd64, not a macro wrapper
around KfAcquireSpinLock()
- NdisFreeBuffer() is actually IoFreeMdl(). I had to change the whole
NDIS_BUFFER API a bit to accomodate this.
Bugs fixed along the way:
- IoAllocateMdl() always returned NULL
- kern_windrv.c:windrv_unload() wasn't releasing private driver object
extensions correctly (found thanks to memguard)
This has only been tested with the driver for the Broadcom 802.11g
chipset, which was the only Windows/x86-64 driver I could find.
2005-02-16 05:41:18 +00:00
|
|
|
strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
|
|
|
|
strcasecmp(manf->vals[1], "NTamd64") == 0)) {
|
2004-03-07 02:49:06 +00:00
|
|
|
/* Handle Windows XP INF files. */
|
|
|
|
snprintf(xpsec, sizeof(xpsec), "%s.%s",
|
|
|
|
manf->vals[0], manf->vals[1]);
|
|
|
|
sec = find_section(xpsec);
|
|
|
|
} else
|
|
|
|
sec = find_section(manf->vals[0]);
|
|
|
|
|
|
|
|
/* See if there are any PCMCIA device definitions. */
|
|
|
|
|
|
|
|
TAILQ_FOREACH(assign, &ah, link) {
|
|
|
|
if (assign->section == sec) {
|
|
|
|
dev = find_assign("strings", assign->key);
|
|
|
|
if (strcasestr(assign->vals[1], "PCMCIA") != NULL) {
|
|
|
|
found++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
found = 0;
|
|
|
|
|
|
|
|
/* Emit start of PCMCIA device table */
|
|
|
|
fprintf (ofp, "#define NDIS_PCMCIA_DEV_TABLE");
|
|
|
|
|
|
|
|
retry:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now run through all the device names listed
|
|
|
|
* in the manufacturer section and dump out the
|
|
|
|
* device descriptions and vendor/device IDs.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TAILQ_FOREACH(assign, &ah, link) {
|
|
|
|
if (assign->section == sec) {
|
|
|
|
dev = find_assign("strings", assign->key);
|
|
|
|
/* Emit device IDs. */
|
|
|
|
if (strcasestr(assign->vals[1], "PCMCIA") != NULL)
|
2003-12-11 22:38:14 +00:00
|
|
|
dump_pcmcia_id(assign->vals[1]);
|
2004-03-07 02:49:06 +00:00
|
|
|
else
|
|
|
|
continue;
|
2003-12-11 22:38:14 +00:00
|
|
|
/* Emit device description */
|
2003-12-11 23:37:56 +00:00
|
|
|
fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
|
2004-01-27 09:05:52 +00:00
|
|
|
found++;
|
2003-12-11 22:38:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-01-27 09:05:52 +00:00
|
|
|
/* Someone tried to fool us. Shame on them. */
|
|
|
|
if (!found) {
|
|
|
|
found++;
|
|
|
|
sec = find_section(manf->vals[0]);
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
2003-12-11 22:38:14 +00:00
|
|
|
/* Emit end of table */
|
|
|
|
|
2003-12-11 23:37:56 +00:00
|
|
|
fprintf(ofp, "\n\n");
|
|
|
|
|
2003-12-11 22:38:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2003-12-18 03:51:21 +00:00
|
|
|
dump_addreg(const char *s, int devidx)
|
2003-12-11 22:38:14 +00:00
|
|
|
{
|
|
|
|
struct section *sec;
|
|
|
|
struct reg *reg;
|
|
|
|
|
|
|
|
/* Find the addreg section */
|
|
|
|
sec = find_section(s);
|
|
|
|
|
|
|
|
/* Dump all the keys defined in it. */
|
|
|
|
TAILQ_FOREACH(reg, &rh, link) {
|
|
|
|
/*
|
|
|
|
* Keys with an empty subkey are very easy to parse,
|
|
|
|
* so just deal with them here. If a parameter key
|
|
|
|
* of the same name also exists, prefer that one and
|
|
|
|
* skip this one.
|
|
|
|
*/
|
|
|
|
if (reg->section == sec) {
|
|
|
|
if (reg->subkey == NULL) {
|
|
|
|
fprintf(ofp, "\n\t{ \"%s\",", reg->key);
|
|
|
|
fprintf(ofp,"\n\t\"%s \",", reg->key);
|
2003-12-18 03:51:21 +00:00
|
|
|
fprintf(ofp, "\n\t{ \"%s\" }, %d },",
|
2003-12-11 22:38:14 +00:00
|
|
|
reg->value == NULL ? "" :
|
2003-12-18 03:51:21 +00:00
|
|
|
stringcvt(reg->value), devidx);
|
2004-01-13 00:29:17 +00:00
|
|
|
} else if (strncasecmp(reg->subkey,
|
|
|
|
"Ndi\\params", strlen("Ndi\\params")-1) == 0 &&
|
2004-01-23 22:28:22 +00:00
|
|
|
(reg->key != NULL && strcasecmp(reg->key,
|
|
|
|
"ParamDesc") == 0))
|
2003-12-18 03:51:21 +00:00
|
|
|
dump_paramreg(sec, reg, devidx);
|
2003-12-11 22:38:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dump_enumreg(const struct section *s, const struct reg *r)
|
|
|
|
{
|
|
|
|
struct reg *reg;
|
|
|
|
char enumkey[256];
|
|
|
|
|
|
|
|
sprintf(enumkey, "%s\\enum", r->subkey);
|
|
|
|
TAILQ_FOREACH(reg, &rh, link) {
|
|
|
|
if (reg->section != s)
|
|
|
|
continue;
|
|
|
|
if (reg->subkey == NULL || strcasecmp(reg->subkey, enumkey))
|
|
|
|
continue;
|
2003-12-12 03:40:05 +00:00
|
|
|
fprintf(ofp, " [%s=%s]", reg->key,
|
|
|
|
stringcvt(reg->value));
|
2003-12-11 22:38:14 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dump_editreg(const struct section *s, const struct reg *r)
|
|
|
|
{
|
|
|
|
struct reg *reg;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(reg, &rh, link) {
|
|
|
|
if (reg->section != s)
|
|
|
|
continue;
|
|
|
|
if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
|
|
|
|
continue;
|
2004-01-23 22:28:22 +00:00
|
|
|
if (reg->key == NULL)
|
|
|
|
continue;
|
2003-12-11 22:38:14 +00:00
|
|
|
if (strcasecmp(reg->key, "LimitText") == 0)
|
|
|
|
fprintf(ofp, " [maxchars=%s]", reg->value);
|
|
|
|
if (strcasecmp(reg->key, "Optional") == 0 &&
|
|
|
|
strcmp(reg->value, "1") == 0)
|
|
|
|
fprintf(ofp, " [optional]");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Use this for int too */
|
|
|
|
static void
|
|
|
|
dump_dwordreg(const struct section *s, const struct reg *r)
|
|
|
|
{
|
|
|
|
struct reg *reg;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(reg, &rh, link) {
|
|
|
|
if (reg->section != s)
|
|
|
|
continue;
|
|
|
|
if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
|
|
|
|
continue;
|
2004-01-23 22:28:22 +00:00
|
|
|
if (reg->key == NULL)
|
|
|
|
continue;
|
2003-12-11 22:38:14 +00:00
|
|
|
if (strcasecmp(reg->key, "min") == 0)
|
|
|
|
fprintf(ofp, " [min=%s]", reg->value);
|
|
|
|
if (strcasecmp(reg->key, "max") == 0)
|
|
|
|
fprintf(ofp, " [max=%s]", reg->value);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2003-12-18 03:51:21 +00:00
|
|
|
dump_defaultinfo(const struct section *s, const struct reg *r, int devidx)
|
2003-12-11 22:38:14 +00:00
|
|
|
{
|
|
|
|
struct reg *reg;
|
|
|
|
TAILQ_FOREACH(reg, &rh, link) {
|
|
|
|
if (reg->section != s)
|
|
|
|
continue;
|
|
|
|
if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
|
|
|
|
continue;
|
2004-01-23 22:28:22 +00:00
|
|
|
if (reg->key == NULL || strcasecmp(reg->key, "Default"))
|
2003-12-11 22:38:14 +00:00
|
|
|
continue;
|
2003-12-18 03:51:21 +00:00
|
|
|
fprintf(ofp, "\n\t{ \"%s\" }, %d },", reg->value == NULL ? "" :
|
2003-12-30 00:30:45 +00:00
|
|
|
stringcvt(reg->value), devidx);
|
2003-12-11 22:38:14 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dump_paramdesc(const struct section *s, const struct reg *r)
|
|
|
|
{
|
|
|
|
struct reg *reg;
|
|
|
|
TAILQ_FOREACH(reg, &rh, link) {
|
|
|
|
if (reg->section != s)
|
|
|
|
continue;
|
|
|
|
if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
|
|
|
|
continue;
|
2004-01-23 22:28:22 +00:00
|
|
|
if (reg->key == NULL || strcasecmp(reg->key, "ParamDesc"))
|
2003-12-11 22:38:14 +00:00
|
|
|
continue;
|
|
|
|
fprintf(ofp, "\n\t\"%s", stringcvt(r->value));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dump_typeinfo(const struct section *s, const struct reg *r)
|
|
|
|
{
|
|
|
|
struct reg *reg;
|
|
|
|
TAILQ_FOREACH(reg, &rh, link) {
|
|
|
|
if (reg->section != s)
|
|
|
|
continue;
|
|
|
|
if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
|
|
|
|
continue;
|
2004-01-23 22:28:22 +00:00
|
|
|
if (reg->key == NULL)
|
|
|
|
continue;
|
2003-12-11 22:38:14 +00:00
|
|
|
if (strcasecmp(reg->key, "type"))
|
|
|
|
continue;
|
|
|
|
if (strcasecmp(reg->value, "dword") == 0 ||
|
|
|
|
strcasecmp(reg->value, "int") == 0)
|
|
|
|
dump_dwordreg(s, r);
|
|
|
|
if (strcasecmp(reg->value, "enum") == 0)
|
|
|
|
dump_enumreg(s, r);
|
|
|
|
if (strcasecmp(reg->value, "edit") == 0)
|
|
|
|
dump_editreg(s, r);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2003-12-18 03:51:21 +00:00
|
|
|
dump_paramreg(const struct section *s, const struct reg *r, int devidx)
|
2003-12-11 22:38:14 +00:00
|
|
|
{
|
|
|
|
const char *keyname;
|
|
|
|
|
|
|
|
keyname = r->subkey + strlen("Ndi\\params\\");
|
|
|
|
fprintf(ofp, "\n\t{ \"%s\",", keyname);
|
|
|
|
dump_paramdesc(s, r);
|
|
|
|
dump_typeinfo(s, r);
|
|
|
|
fprintf(ofp, "\",");
|
2003-12-18 03:51:21 +00:00
|
|
|
dump_defaultinfo(s, r, devidx);
|
2003-12-11 22:38:14 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-02-16 18:37:14 +00:00
|
|
|
static void
|
2003-12-11 22:38:14 +00:00
|
|
|
dump_regvals(void)
|
|
|
|
{
|
2003-12-18 03:51:21 +00:00
|
|
|
struct assign *manf, *dev;
|
2003-12-11 22:38:14 +00:00
|
|
|
struct section *sec;
|
|
|
|
struct assign *assign;
|
|
|
|
char sname[256];
|
2004-01-27 09:05:52 +00:00
|
|
|
int found = 0, i, is_winxp = 0, is_winnt = 0, devidx = 0;
|
2004-01-02 21:13:21 +00:00
|
|
|
|
|
|
|
/* Find signature to check for special case of WinNT. */
|
|
|
|
assign = find_assign("version", "signature");
|
|
|
|
if (strcasecmp(assign->vals[0], "$windows nt$") == 0)
|
|
|
|
is_winnt++;
|
2003-12-11 22:38:14 +00:00
|
|
|
|
|
|
|
/* Find manufacturer name */
|
|
|
|
manf = find_assign("Manufacturer", NULL);
|
|
|
|
|
|
|
|
/* Find manufacturer section */
|
2003-12-12 03:40:05 +00:00
|
|
|
if (manf->vals[1] != NULL &&
|
2003-12-13 08:48:35 +00:00
|
|
|
(strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
|
2004-01-03 02:25:21 +00:00
|
|
|
strcasecmp(manf->vals[1], "NTx86") == 0 ||
|
Add support for Windows/x86-64 binaries to Project Evil.
Ville-Pertti Keinonen (will at exomi dot comohmygodnospampleasekthx)
deserves a big thanks for submitting initial patches to make it
work. I have mangled his contributions appropriately.
The main gotcha with Windows/x86-64 is that Microsoft uses a different
calling convention than everyone else. The standard ABI requires using
6 registers for argument passing, with other arguments on the stack.
Microsoft uses only 4 registers, and requires the caller to leave room
on the stack for the register arguments incase the callee needs to
spill them. Unlike x86, where Microsoft uses a mix of _cdecl, _stdcall
and _fastcall, all routines on Windows/x86-64 uses the same convention.
This unfortunately means that all the functions we export to the
driver require an intermediate translation wrapper. Similarly, we have
to wrap all calls back into the driver binary itself.
The original patches provided macros to wrap every single routine at
compile time, providing a secondary jump table with a customized
wrapper for each exported routine. I decided to use a different approach:
the call wrapper for each function is created from a template at
runtime, and the routine to jump to is patched into the wrapper as
it is created. The subr_pe module has been modified to patch in the
wrapped function instead of the original. (On x86, the wrapping
routine is a no-op.)
There are some minor API differences that had to be accounted for:
- KeAcquireSpinLock() is a real function on amd64, not a macro wrapper
around KfAcquireSpinLock()
- NdisFreeBuffer() is actually IoFreeMdl(). I had to change the whole
NDIS_BUFFER API a bit to accomodate this.
Bugs fixed along the way:
- IoAllocateMdl() always returned NULL
- kern_windrv.c:windrv_unload() wasn't releasing private driver object
extensions correctly (found thanks to memguard)
This has only been tested with the driver for the Broadcom 802.11g
chipset, which was the only Windows/x86-64 driver I could find.
2005-02-16 05:41:18 +00:00
|
|
|
strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
|
|
|
|
strcasecmp(manf->vals[1], "NTamd64") == 0)) {
|
2003-12-12 03:40:05 +00:00
|
|
|
is_winxp++;
|
|
|
|
/* Handle Windows XP INF files. */
|
|
|
|
snprintf(sname, sizeof(sname), "%s.%s",
|
|
|
|
manf->vals[0], manf->vals[1]);
|
|
|
|
sec = find_section(sname);
|
|
|
|
} else
|
|
|
|
sec = find_section(manf->vals[0]);
|
2003-12-11 22:38:14 +00:00
|
|
|
|
|
|
|
/* Emit start of block */
|
|
|
|
fprintf (ofp, "ndis_cfg ndis_regvals[] = {");
|
|
|
|
|
2004-01-27 09:05:52 +00:00
|
|
|
retry:
|
|
|
|
|
2003-12-11 22:38:14 +00:00
|
|
|
TAILQ_FOREACH(assign, &ah, link) {
|
|
|
|
if (assign->section == sec) {
|
2004-01-27 09:05:52 +00:00
|
|
|
found++;
|
2003-12-12 03:40:05 +00:00
|
|
|
/*
|
|
|
|
* Find all the AddReg sections.
|
|
|
|
* Look for section names with .NT, unless
|
|
|
|
* this is a WinXP .INF file.
|
|
|
|
*/
|
Add support for Windows/x86-64 binaries to Project Evil.
Ville-Pertti Keinonen (will at exomi dot comohmygodnospampleasekthx)
deserves a big thanks for submitting initial patches to make it
work. I have mangled his contributions appropriately.
The main gotcha with Windows/x86-64 is that Microsoft uses a different
calling convention than everyone else. The standard ABI requires using
6 registers for argument passing, with other arguments on the stack.
Microsoft uses only 4 registers, and requires the caller to leave room
on the stack for the register arguments incase the callee needs to
spill them. Unlike x86, where Microsoft uses a mix of _cdecl, _stdcall
and _fastcall, all routines on Windows/x86-64 uses the same convention.
This unfortunately means that all the functions we export to the
driver require an intermediate translation wrapper. Similarly, we have
to wrap all calls back into the driver binary itself.
The original patches provided macros to wrap every single routine at
compile time, providing a secondary jump table with a customized
wrapper for each exported routine. I decided to use a different approach:
the call wrapper for each function is created from a template at
runtime, and the routine to jump to is patched into the wrapper as
it is created. The subr_pe module has been modified to patch in the
wrapped function instead of the original. (On x86, the wrapping
routine is a no-op.)
There are some minor API differences that had to be accounted for:
- KeAcquireSpinLock() is a real function on amd64, not a macro wrapper
around KfAcquireSpinLock()
- NdisFreeBuffer() is actually IoFreeMdl(). I had to change the whole
NDIS_BUFFER API a bit to accomodate this.
Bugs fixed along the way:
- IoAllocateMdl() always returned NULL
- kern_windrv.c:windrv_unload() wasn't releasing private driver object
extensions correctly (found thanks to memguard)
This has only been tested with the driver for the Broadcom 802.11g
chipset, which was the only Windows/x86-64 driver I could find.
2005-02-16 05:41:18 +00:00
|
|
|
|
2003-12-13 08:48:35 +00:00
|
|
|
if (is_winxp) {
|
|
|
|
sprintf(sname, "%s.NTx86", assign->vals[0]);
|
|
|
|
dev = find_assign(sname, "AddReg");
|
Add support for Windows/x86-64 binaries to Project Evil.
Ville-Pertti Keinonen (will at exomi dot comohmygodnospampleasekthx)
deserves a big thanks for submitting initial patches to make it
work. I have mangled his contributions appropriately.
The main gotcha with Windows/x86-64 is that Microsoft uses a different
calling convention than everyone else. The standard ABI requires using
6 registers for argument passing, with other arguments on the stack.
Microsoft uses only 4 registers, and requires the caller to leave room
on the stack for the register arguments incase the callee needs to
spill them. Unlike x86, where Microsoft uses a mix of _cdecl, _stdcall
and _fastcall, all routines on Windows/x86-64 uses the same convention.
This unfortunately means that all the functions we export to the
driver require an intermediate translation wrapper. Similarly, we have
to wrap all calls back into the driver binary itself.
The original patches provided macros to wrap every single routine at
compile time, providing a secondary jump table with a customized
wrapper for each exported routine. I decided to use a different approach:
the call wrapper for each function is created from a template at
runtime, and the routine to jump to is patched into the wrapper as
it is created. The subr_pe module has been modified to patch in the
wrapped function instead of the original. (On x86, the wrapping
routine is a no-op.)
There are some minor API differences that had to be accounted for:
- KeAcquireSpinLock() is a real function on amd64, not a macro wrapper
around KfAcquireSpinLock()
- NdisFreeBuffer() is actually IoFreeMdl(). I had to change the whole
NDIS_BUFFER API a bit to accomodate this.
Bugs fixed along the way:
- IoAllocateMdl() always returned NULL
- kern_windrv.c:windrv_unload() wasn't releasing private driver object
extensions correctly (found thanks to memguard)
This has only been tested with the driver for the Broadcom 802.11g
chipset, which was the only Windows/x86-64 driver I could find.
2005-02-16 05:41:18 +00:00
|
|
|
if (dev == NULL) {
|
|
|
|
sprintf(sname, "%s.NT",
|
|
|
|
assign->vals[0]);
|
|
|
|
dev = find_assign(sname, "AddReg");
|
|
|
|
}
|
2003-12-13 08:48:35 +00:00
|
|
|
if (dev == NULL)
|
|
|
|
dev = find_assign(assign->vals[0],
|
|
|
|
"AddReg");
|
|
|
|
} else {
|
2003-12-12 03:40:05 +00:00
|
|
|
sprintf(sname, "%s.NT", assign->vals[0]);
|
|
|
|
dev = find_assign(sname, "AddReg");
|
2004-01-02 21:13:21 +00:00
|
|
|
if (dev == NULL && is_winnt)
|
|
|
|
dev = find_assign(assign->vals[0],
|
|
|
|
"AddReg");
|
2003-12-12 03:40:05 +00:00
|
|
|
}
|
|
|
|
/* Section not found. */
|
|
|
|
if (dev == NULL)
|
|
|
|
continue;
|
2003-12-11 22:38:14 +00:00
|
|
|
for (i = 0; i < W_MAX; i++) {
|
|
|
|
if (dev->vals[i] != NULL)
|
2003-12-18 03:51:21 +00:00
|
|
|
dump_addreg(dev->vals[i], devidx);
|
2003-12-11 22:38:14 +00:00
|
|
|
}
|
2003-12-18 03:51:21 +00:00
|
|
|
devidx++;
|
2003-12-11 22:38:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-01-27 09:05:52 +00:00
|
|
|
if (!found) {
|
|
|
|
sec = find_section(manf->vals[0]);
|
|
|
|
is_winxp = 0;
|
|
|
|
found++;
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
2003-12-18 03:51:21 +00:00
|
|
|
fprintf(ofp, "\n\t{ NULL, NULL, { 0 }, 0 }\n};\n\n");
|
2003-12-11 22:38:14 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
assign_add (const char *a)
|
|
|
|
{
|
|
|
|
struct assign *assign;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
assign = malloc(sizeof(struct assign));
|
|
|
|
bzero(assign, sizeof(struct assign));
|
|
|
|
assign->section = TAILQ_LAST(&sh, section_head);
|
|
|
|
assign->key = sstrdup(a);
|
|
|
|
for (i = 0; i < idx; i++)
|
|
|
|
assign->vals[(idx - 1) - i] = sstrdup(words[i]);
|
|
|
|
TAILQ_INSERT_TAIL(&ah, assign, link);
|
|
|
|
|
|
|
|
clear_words();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
define_add (const char *d __unused)
|
|
|
|
{
|
|
|
|
#ifdef notdef
|
|
|
|
fprintf(stderr, "define \"%s\"\n", d);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
sstrdup(const char *str)
|
|
|
|
{
|
|
|
|
if (str != NULL && strlen(str))
|
|
|
|
return (strdup(str));
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
satoi (const char *nptr)
|
|
|
|
{
|
|
|
|
if (nptr != NULL && strlen(nptr))
|
|
|
|
return (atoi(nptr));
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
regkey_add (const char *r)
|
|
|
|
{
|
|
|
|
struct reg *reg;
|
|
|
|
|
|
|
|
reg = malloc(sizeof(struct reg));
|
|
|
|
bzero(reg, sizeof(struct reg));
|
|
|
|
reg->section = TAILQ_LAST(&sh, section_head);
|
|
|
|
reg->root = sstrdup(r);
|
|
|
|
reg->subkey = sstrdup(words[3]);
|
|
|
|
reg->key = sstrdup(words[2]);
|
|
|
|
reg->flags = satoi(words[1]);
|
|
|
|
reg->value = sstrdup(words[0]);
|
|
|
|
TAILQ_INSERT_TAIL(&rh, reg, link);
|
|
|
|
|
|
|
|
free(__DECONST(char *, r));
|
|
|
|
clear_words();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
push_word (const char *w)
|
|
|
|
{
|
|
|
|
if (w && strlen(w))
|
|
|
|
words[idx++] = w;
|
|
|
|
else
|
|
|
|
words[idx++] = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
clear_words (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < idx; i++) {
|
|
|
|
if (words[i]) {
|
|
|
|
free(__DECONST(char *, words[i]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
idx = 0;
|
|
|
|
bzero(words, sizeof(words));
|
|
|
|
return;
|
|
|
|
}
|