|
Don asked me to submit my previous posting in pieces.
So here is part one:
Here is first a C/400 program to print the System Entry Point Table (SEPT).
/* Test program to display System Entry Point Table */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/* qsysinc: */
#include <pointer.h>
#include <mimchobs.h>
#include <mispcobj.h>
#include <miptrnam.h>
#include <qliept.h>
static _MPTR_Template_T *mptr_area;
void main(void){
int i;
_OPENPTR *inv_sys;
i = sizeof(_MPTR_Template_T);
mptr_area = malloc(i);
mptr_area->Obj_Ptr.Template_Size = i;
for(i=0; i<WLISRHNMTBL_DIM; i++)
{
inv_sys = (((_SYSPTR **)_SYSEPT()) + i);
if (*inv_sys != NULL)
{
matptr(mptr_area, *inv_sys);
printf("Entry %d is %10.10s %10.10s\n", i,
mptr_area->Obj_Ptr.Library_ID.Name,
mptr_area->Obj_Ptr.Object_ID.Name);
}
else
{
printf("Entry %d is **null**\n", i);
}
}
free(mptr_area);
}
When run under Security Level 30, the program prints out 6245 entries. When
run under level 40, the program bombs right away with a 'security
violation'. The program uses the MATPTR API, which is documented in the
usual AS/400 manuals.
Under any Security Level you can always dump the SEPT using the DUMPSYSOBJ
command:
DMPSYSOBJ OBJ(QINSEPT) CONTEXT(QSYS)
When you do that and select the QPSRVDMP spool file with WRKSPLF you see
something like the following; find the POINTERS section:
Display Spooled File
File . . . . . : QPSRVDMP Page/Line 54/47
Control . . . . . Columns 1 - 78
Find . . . . . . POINTERS
*...+....1....+....2....+....3....+....4....+....5....+....6....+....7..
.POINTERS-
000000 SYP 02 01 QT3REQIO 04 01 QSYS
000010 SYP 02 01 QWSCLOSE 04 01 QSYS
000020 SYP 02 01 QSFGET 04 01 QSYS
000030 SYP 02 01 QWSOPEN 04 01 QSYS
000040 SYP 02 01 QWSPBDVR 04 01 QSYS
000050 SYP 02 01 QWSRST 04 01 QSYS
000060 SYP 02 01 QWSRTSFL 04 01 QSYS
000070 SYP 02 01 QSFCRT 04 01 QSYS
000080 SYP 02 01 QWSSPEND 04 01 QSYS
000090 SYP 02 01 QDCVRX 04 01 QSYS
0000A0 SYP 02 01 QDMCLOSE 04 01 QSYS
0000B0 SYP 02 01 QDMCOPEN 04 01 QSYS
0000C0 SYP 02 01 QDBCLOSE 04 01 QSYS
0000D0 SYP 02 01 QDBGETDR 04 01 QSYS
0000E0 SYP 02 01 QDBGETKY 04 01 QSYS
0000F0 SYP 02 01 QDBGETSQ 04 01 QSYS
000100 SYP 02 01 QDBOPEN 04 01 QSYS
000110 SYP 02 01 QDBPUT 04 01 QSYS
000120 SYP 02 01 QDBUDR 04 01 QSYS
000130 SYP 02 01 QSPBPPRT 04 01 QSYS
000140 SYP 02 01 QOESETEX 04 01 QSYS
000150 SYP 02 01 QWSPUT 04 01 QSYS
000160 SYP 02 01 QWSMEEH 04 01 QSYS
000170 SYP 02 01 QWSMSG 04 01 QSYS
000180 SYP 02 01 QWSPTMSG 04 01 QSYS
000190 SYP 02 01 QLPCTLIN 04 01 QSYS
0001A0 SYP 02 01 QLPTRANS 04 01 QSYS
0001B0 SYP 02 01 QWCITUNR 04 01 QSYS
0001C0 SYP 02 01 QTIMAIN1 04 01 QSYS
. . . etc
It takes 144 seconds to produce the dump. The dump shows programs in their
context (QSYS). One could capture this output in a file and work on each
entry.
MI Program DSPSEPT to Materialize the SEPT.
For simplicity in experimentation the program sends its resulting output for
each entry to the job's message queue. Stop it with the System Request key,
then answer '2'. Don't worry about the details, go straight to the
discussion after the listing.
DCL SPC * BASPCO;
DCL SPCPTR .SEPT_PCO DIR; /* 1ST ENTRY */
DCL SYSPTR .SEPT(6440) BAS(.SEPT_PCO);
DCL CON MAX_SEPT BIN(2) INIT(6440); /* VERSION DEPENDENT */
DCL DD ENTRY_NBR BIN(2);
DCL DD INFO CHAR(77) BDRY(16);
DCL DD INFO_PRV BIN ( 4) DEF(INFO) POS( 1) INIT(77);
DCL DD INFO_AVL BIN ( 4) DEF(INFO) POS( 5);
DCL DD INFO_PTR_TYPE CHAR( 1) DEF(INFO) POS( 9);
DCL DD INFO_LIB_ID CHAR(32) DEF(INFO) POS(10);
DCL DD INFO_LIB_TYPES CHAR( 2) DEF(INFO_LIB_ID) POS(1);
DCL DD INFO_LIB_NAME CHAR(30) DEF(INFO_LIB_ID) POS(3);
DCL DD INFO_OBJ_ID CHAR(32) DEF(INFO) POS(42);
DCL DD INFO_OBJ_TYPES CHAR( 2) DEF(INFO_OBJ_ID) POS(1);
DCL DD INFO_OBJ_NAME CHAR(30) DEF(INFO_OBJ_ID) POS(3);
DCL DD INFO_BITS CHAR( 4) DEF(INFO) POS(74);
DCL SPCPTR .INFO INIT(INFO);
DCL SYSPTR .FORGED; /* SYSTEM POINTER TO FORGE */
DCL INSPTR RETURN; /* RETURN PTR FOR CALLI */
ENTRY * EXT;
CPYNV ENTRY_NBR, 0;
NEXT_ENTRY:
ADDN(S) ENTRY_NBR, 1;
SETSPFP .FORGED, .SEPT(ENTRY_NBR); /* FORGE POINTER */
MATPTR .INFO, .FORGED; BRK "1";
CALLI SHOW_OBJECT, *, RETURN; /* SHOW RESULT TO MSGQ */
TEST_ENTRY:
CMPNV(B) ENTRY_NBR, MAX_SEPT /LO(NEXT_ENTRY);
RTX *;
/******* SEND MESSAGE HANDLING ********/
DCL DD MSG_ID CHAR (7) INIT(" ");
DCL SPCPTR .MSG_ID INIT(MSG_ID);
DCL DD MSG_FILE CHAR(20) INIT(" ");
DCL SPCPTR .MSG_FILE INIT(MSG_FILE);
DCL DD MSG_TEXT CHAR(74);
DCL DD MSG_ENTRY_NBR ZND(4,0) DEF(MSG_TEXT) POS( 1);
DCL DD * CHAR( 1) DEF(MSG_TEXT) POS( 5) INIT(":");
DCL DD MSG_OBJ_OBJ CHAR(30) DEF(MSG_TEXT) POS( 6);
DCL DD MSG_OBJ_LIB CHAR(30) DEF(MSG_TEXT) POS(36);
DCL DD * CHAR( 1) DEF(MSG_TEXT) POS(66) INIT(" ");
DCL DD MSG_OBJ_BITS CHAR( 8) DEF(MSG_TEXT) POS(67);
DCL SPCPTR .MSG_TEXT INIT(MSG_TEXT);
DCL DD MSG_SIZE BIN( 4) INIT(74);
DCL SPCPTR .MSG_SIZE INIT(MSG_SIZE);
DCL DD MSG_TYPE CHAR(10) INIT("*INFO ");
DCL SPCPTR .MSG_TYPE INIT(MSG_TYPE);
DCL DD MSG_QS CHAR(20) INIT("*REQUESTER ");
DCL SPCPTR .MSG_QS INIT(MSG_QS);
DCL DD MSG_QSN BIN( 4) INIT(1);
DCL SPCPTR .MSG_QSN INIT(MSG_QSN);
DCL DD REPLY_Q CHAR(20) INIT(" ");
DCL SPCPTR .REPLY_Q INIT(REPLY_Q);
DCL DD MSG_KEY CHAR( 4);
DCL SPCPTR .MSG_KEY INIT(MSG_KEY);
DCL DD ERR_CODE BIN( 4) INIT(0);
DCL SPCPTR .ERR_CODE INIT(ERR_CODE);
DCL OL QMHSNDMOL (.MSG_ID, .MSG_FILE, .MSG_TEXT, .MSG_SIZE,
.MSG_TYPE, .MSG_QS, .MSG_QSN, .REPLY_Q,
.MSG_KEY, .ERR_CODE) ARG;
ENTRY SHOW_OBJECT INT; /* SHOW OBJECT INFO */
CPYNV MSG_ENTRY_NBR, ENTRY_NBR;
CPYBLA MSG_OBJ_OBJ, INFO_OBJ_NAME;
CPYBLA MSG_OBJ_LIB, INFO_LIB_NAME;
CVTHC MSG_OBJ_BITS, INFO_BITS; /* HEX TO CHAR */
CALLX .SEPT(4268), QMHSNDMOL, *; /* SEND MSG TO MSGQ */
B RETURN;
/******* EXCEPTION HANDLING ********/
DCL EXCM EXCEPTION_MONITOR EXCID(H'0000') /* ALL */
BP(ERROR_DETECTED) IMD;
ERROR_DETECTED:
CPYBLAP INFO_OBJ_NAME, "*PROTECTED", " ";
CPYBLAP INFO_LIB_NAME, "QSYS", " ";
CPYBLA INFO_BITS, X'00000000';
CALLI SHOW_OBJECT, *, RETURN;
B TEST_ENTRY;
PEND;
The crucial instructions are:
SETSPFP .FORGED, .SEPT(ENTRY_NBR); /* FORGE POINTER */
MATPTR .INFO, .FORGED;
If you simply try to materialize the entry point, that is:
MATPTR .INFO, .SEPT(ENTRY_NBR);
you get an exception ('Object domain or hardware storage protection
violation'). By setting another system pointer, .FORGED, from the entry
point (the SETSPFP instruction) you essentially forge a new pointer from the
old. This new pointer can be materialized in some cases, bypassing the
security integrity check for the SEPT object itself. I've marked (with OK)
the entries that can be materialized in the following table:
000000 SYP 02 01 QT3REQIO 04 01 QSYS
000010 SYP 02 01 QWSCLOSE 04 01 QSYS
000020 SYP 02 01 QSFGET 04 01 QSYS
000030 SYP 02 01 QWSOPEN 04 01 QSYS
000040 SYP 02 01 QWSPBDVR 04 01 QSYS
000050 SYP 02 01 QWSRST 04 01 QSYS
000060 SYP 02 01 QWSRTSFL 04 01 QSYS
000070 SYP 02 01 QSFCRT 04 01 QSYS
000080 SYP 02 01 QWSSPEND 04 01 QSYS
000090 SYP 02 01 QDCVRX 04 01 QSYS
0000A0 SYP 02 01 QDMCLOSE OK 04 01 QSYS
0000B0 SYP 02 01 QDMCOPEN OK 04 01 QSYS
0000C0 SYP 02 01 QDBCLOSE 04 01 QSYS
0000D0 SYP 02 01 QDBGETDR OK 04 01 QSYS
0000E0 SYP 02 01 QDBGETKY OK 04 01 QSYS
0000F0 SYP 02 01 QDBGETSQ OK 04 01 QSYS
000100 SYP 02 01 QDBOPEN 04 01 QSYS
000110 SYP 02 01 QDBPUT OK 04 01 QSYS
000120 SYP 02 01 QDBUDR OK 04 01 QSYS
000130 SYP 02 01 QSPBPPRT 04 01 QSYS
000140 SYP 02 01 QOESETEX 04 01 QSYS
000150 SYP 02 01 QWSPUT OK 04 01 QSYS
000160 SYP 02 01 QWSMEEH 04 01 QSYS
. . .
If you display the program information (DSPPGM PGM(QSYS/QDMCLOSE) for two
entries (one that can be materialized and one that cannot) you see something
like this:
Program . . . . . .. . . . . .: QDMCLOSE QDBCLOSE
Program creation date/time .. .. : 03/18/98 15:36:56 05/18/98
23:04:18
Type of program . . . . . . . . : OPM OPM
Source file . . . . . . . . . . :
Library . . . . . . . . . . . :
Source member . . . . . . . . . :
Source file change date/time . . :
Observable information . . . . . : *NONE *NONE
User profile . . . . . . . . . . : *USER *USER
Use adopted authority . . . . . : *YES *YES
Fix decimal data . . . . . . . . : *NO *NO
Text description . . . . . . . . :
Program size (bytes) . . . . . . : 49152 32768
Associated space size (bytes) . : 0 0
Static storage size (bytes) . . : 0 0
Automatic storage size (bytes) . : 2208 1488
Program state . . . . . . . . . : *SYSTEM *SYSTEM
Program domain . . . . . . . . . : *USER *SYSTEM
Compiler . . . . . . . . . . . . : V4R3M0
V4R3M0
Earliest release for running. .. : V4R3M0 V4R3M0
Conversion required . . . . . . : *NO *NO
Sort sequence . . . . . . . . . : *HEX *HEX
Language identifier . . . . . . : *JOBRUN *JOBRUN
Optimization . . . . . . . . . . : *OPTIMIZE *OPTIMIZE
Paging pool . . . . . . . . . . : *USER *USER
Update PASA . . . . . . . . . . : *UPDPASA *NOUPDPASA
Clear PASA . . . . . . . . . . . : *CLRPASA *NOCLRPASA
Paging amount . . . . . . . . . : *BLOCK *BLOCK
The only real difference is that QDMCLOSE is in the *USER domain and
QDBCLOSE is in the *SYSTEM domain. To put it differently: QDMCLOSE is for
general use (this does not necessarily mean that it is a documented API;
e.g. QDBPUT is not) and QDBCLOSE is for system use only.
With the MATPTR MI-instruction you had to forge the pointer to access an
entry in the SEPT. There is another instruction, Materialize System Object -
MATSOBJ, that can materialize a system object; e.g.:
MATSOBJ .INFO, .SEPT(ENTRY_NBR);
This works directly without using a forged pointer. However, you still
cannot materialize objects in the system domain (in spite of the name of the
MI-instruction).
Why Are We Doing This
The System Entry Point Table (SEPT) is important, because the programs in it
are before any programs in the library list and are the basic operating
system calls (e.g. to open files, read records, etc). If you could place one
of your own programs here in lieu of a standard entry point, you could act
as a Trojan Horse and essentially bypass most security. A minimum defense
against this would be to print a listing of all the programs including their
properties.
If you are running under at least Security Level 40, you are supposedly
protected against tampering with the SEPT so you need only to worry about
the entries you can have access to. The problem here is that you want to be
*sure* that it has not been tampered with.
+---
| This is the MI Programmers Mailing List!
| To submit a new message, send your mail to MI400@midrange.com.
| To subscribe to this list send email to MI400-SUB@midrange.com.
| To unsubscribe from this list send email to MI400-UNSUB@midrange.com.
| Questions should be directed to the list owner/operator: dr2@cssas400.com
+---
As an Amazon Associate we earn from qualifying purchases.
This mailing list archive is Copyright 1997-2025 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].
Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.