Simba Code:
{=======================================================================================]
| |
| _____ _ _ _____ _ _ _____ |
| | __|_|_____| |_ ___ | __|___ ___|_|___| |_ | __|___ ___ ___ ___ ___ ___ |
| |__ | | | . | .'| |__ | _| _| | . | _| |__ | _| .'| | | -_| _| |
| |_____|_|_|_|_|___|__,| |_____|___|_| |_| _|_| |_____|___|__,|_|_|_|_|___|_| |
| |_| |
| |
[=======================================================================================}
const
COMMENT_FILTER = '@'; // CHAR, NOT STRING! Used in debug box for displaying the filtered comments (doesn't effect scan, as these will be empty chars in filteredScriptText for scan).
STRING_FILTER = '%'; // CHAR, NOT STRING! Used in debug box for displaying the filtered strings (doesn't effect scan, these will be empty chars in filteredScriptText for scan).
STRICT_PLAYERS_INFO_DETECTION = False; // NOTE: Enabling this will pick up less falsepositives.
// However, then script wont detect all the PASS/PIN/NAME's either, because it can be quite tricky sometimes (with..do issue).
// Disabled by default - picks up those player info things a lot better.
DEBUG_SCAN_STEPS = True;
DEFAULT = 'Times New Roman';
VERSION = 2.12; // Don't touch... Extension version.
POINTS_LOW = 1; // DON'T TOUCH!
POINTS_MEDIUM = 2; // DON'T TOUCH!
POINTS_HIGH = 4; // DON'T TOUCH!
POINTS_VERY_HIGH = 6; // DON'T TOUCH!
type
TMatchMethod = (mmAll, mmIgnoreCase, mmOverlap, mmWholeWords, mmStrictWW, mmGreedyRegex);
TMatchMethods = set of TMatchMethod;
TRegexMatch = record
position, size: Integer;
text: string;
end;
TRegexMatchArray = array of TRegexMatch;
T2DRegexMatchArray = array of TRegexMatchArray;
TRegexModifier = (rm_G, rm_I, rm_M, rm_S, rm_X, rm_R);
TRange = record
minimum, maximum: Integer;
end;
TRangeArray = array of TRange;
TThreat = record
line: Integer;
threat: string;
kind: (tk_Socket, tk_HTTP, tk_Web, tk_File, tk_Fishy, tk_Unhuman);
end;
TThreatArray = array of TThreat;
var
DsgnForm, ResultsForm: TForm;
ScriptEdit:TMemo;
debugboxes: array [0..4] of TMemo;
TitleLabel: array[0..1] of TLabel;
Buttons: array[0..1] of TButton;
CheckBoxs: array[0..7] of TCheckBox;
originalScriptText, filteredScriptText, displayScriptText: string;
SocketThreats, HTTPThreats, WebThreats, FileThreats, UnhumanCode, FishyCode, points, scanTimer, currentStep, totalSteps, scanTiming: Integer;
msgSocket, msgHTTP, msgWeb, msgFile, msgUnhuman, msgFishy, steps: string;
pressed, SOCKET_SCAN, HTTP_SCAN, WEB_SCAN, FILE_SCAN, CODE_SCAN, DEBUG_FILTERED_SCRIPT, FILTER_COMMENTS, FILTER_STRINGS: Boolean;
threats: TThreatArray;
linePositions: TIntegerArray;
Tabs: Array[0..1] of TTabSheet;
ResultTabs: Array[0..4] of TTabSheet;
P, P2: TPageControl;
Simba_Menu: TMenuItem;
MenuItems: array[0..5] of TMenuItem;
HelpMenuItems: array[0..1] of TMenuItem;
falsePositives: TRangeArray;
procedure Append(var str: string; data: string);
begin
str := (str + data);
end;
function TextReport: string;
var
h, i: Integer;
li, th, kd, rl, tmp: string;
begin
Result := '';
Append(Result, '*************************************************' + #13#10);
Append(Result, '* _ _ _ _ _ _ _ _ __ *' + #13#10);
Append(Result, '* /_`/ `/_//|/ /_//_`/_// //_// *' + #13#10);
Append(Result, '* ._//_,/ // | / \/_,/ /_// \/ *' + #13#10);
Append(Result, '* *' + #13#10);
Append(Result, '*************************************************' + #13#10);
Append(Result, ' ' + #13#10);
if DEBUG_FILTERED_SCRIPT then
if (displayScriptText <> '') then
begin
Append(Result, '<===============[Filtered Script]===============>' + #13#10);
Append(Result, displayScriptText + #13#10);
Append(Result, '<===============================================>' + #13#10);
Append(Result, ' ' + #13#10);
end;
if DEBUG_SCAN_STEPS then
if (steps <> '') then
begin
debugboxes[0].Lines.Add('<====================[Scan Steps]=====================>' + #13#10);
debugboxes[0].Lines.Add(steps + #13#10);
debugboxes[0].Lines.Add('<=====================================================>' + #13#10);
debugboxes[0].Lines.Add(' ' + #13#10);
end;
if SOCKET_SCAN then
if (msgSocket <> '') then
begin
Append(Result, '<=========[Messages for Socket Threats]=========>' + #13#10);
Append(Result, msgSocket + #13#10);
Append(Result, '<===============================================>' + #13#10);
Append(Result, ' ' + #13#10);
end;
if HTTP_SCAN then
if (msgHTTP <> '') then
begin
Append(Result, '<==========[Messages for HTTP Threats]==========>' + #13#10);
Append(Result, msgHTTP + #13#10);
Append(Result, '<===============================================>' + #13#10);
Append(Result, ' ' + #13#10);
end;
if WEB_SCAN then
if (msgWeb <> '') then
begin
Append(Result, '<===========[Messages for Web Threats]==========>' + #13#10);
Append(Result, msgWeb + #13#10);
Append(Result, '<===============================================>' + #13#10);
Append(Result, ' ' + #13#10);
end;
if FILE_SCAN then
if (msgFile <> '') then
begin
Append(Result, '<===========[Messages for File Threats]=========>' + #13#10);
Append(Result, msgFile + #13#10);
Append(Result, '<===============================================>' + #13#10);
Append(Result, ' ' + #13#10);
end;
if CODE_SCAN then
begin
if (msgFishy <> '') then
begin
Append(Result, '<===========[Messages for Fishy Code]===========>' + #13#10);
Append(Result, msgFishy + #13#10);
Append(Result, '<===============================================>' + #13#10);
Append(Result, ' ' + #13#10);
end;
if (msgUnhuman <> '') then
begin
Append(Result, '<==========[Messages for Unhuman Code]==========>' + #13#10);
Append(Result, msgUnhuman + #13#10);
Append(Result, '<===============================================>' + #13#10);
Append(Result, ' ' + #13#10);
end;
end;
h := High(threats);
if (h > -1) then
begin
Append(Result, '<=============[Lines with Threats]==============>' + #13#10);
Append(Result, ' LINE | KIND | THREAT ' + #13#10);
Append(Result, ' -----+----------------+------------------------ ' + #13#10);
for i := 0 to h do
begin
case (threats[i].line > -1) of
True: li := IntToStr(threats[i].line);
False: li := 'NONE';
end;
case threats[i].kind of
tk_Socket: kd := 'Socket Threat';
tk_HTTP: kd := 'HTTP Threat';
tk_Web: kd := 'Web Threat';
tk_File: kd := 'File Threat';
tk_Fishy: kd := 'Fishy Code';
tk_Unhuman: kd := 'Unhuman Code';
end;
th := threats[i].threat;
Append(Result, ' ' + (li + Padr(' ', (Length(' LINE |') - Length(li)) - 2)) + '| ' + (kd + Padr(' ', (Length(' KIND |') - Length(kd)) - 2)) + '| ' + th + #13#10);
end;
Append(Result, '<===============================================>' + #13#10);
Append(Result, ' ' + #13#10);
end;
case points of
0: rl := 'None';
1..3: rl := 'Low';
4..7: rl := 'Medium';
8..12: rl := 'High';
else
rl := 'Very High';
end;
Append(Result, '<================[Scan Results]=================>' + #13#10);
Append(Result, ' Socket threats' + StringOfChar('.', (47 - (Length('Socket threats') + Length(IntToStr(SocketThreats))))) + IntToStr(SocketThreats) + #13#10);
Append(Result, ' HTTP threats' + StringOfChar('.', (47 - (Length('HTTP threats') + Length(IntToStr(HTTPThreats))))) + IntToStr(HTTPThreats) + #13#10);
Append(Result, ' Web threats' + StringOfChar('.', (47 - (Length('Web threats') + Length(IntToStr(WebThreats))))) + IntToStr(WebThreats) + #13#10);
Append(Result, ' File threats' + StringOfChar('.', (47 - (Length('File threats') + Length(IntToStr(FileThreats))))) + IntToStr(FileThreats) + #13#10);
Append(Result, ' Fishy code' + StringOfChar('.', (47 - (Length('Fishy code') + Length(IntToStr(FishyCode))))) + IntToStr(FishyCode) + #13#10);
Append(Result, ' Unhuman code' + StringOfChar('.', (47 - (Length('Unhuman code') + Length(IntToStr(UnhumanCode))))) + IntToStr(UnhumanCode) + #13#10);
Append(Result, ' -----------------------------------------------' + #13#10);
Append(Result, ' Overall threats' + StringOfChar('.', (47 - (Length('Overall threats') + Length(IntToStr(Length(threats)))))) + IntToStr(Length(threats)) + #13#10);
Append(Result, ' Script Risk Level' + StringOfChar('.', (47 - (Length('Script Risk Level') + Length(rl)))) + rl + #13#10);
Append(Result, '<===============================================>' + #13#10);
Append(Result, ' ' + #13#10);
Append(Result, '<===================[FINISHED]==================>' + #13#10);
Append(Result, ' Remember to visit the thread for latest updates.' + #13#10);
Append(Result, ' Thank you for using! ' + #13#10);
tmp := '~ Total Time Taken ' + IntToStr(GetSystemTime - scanTiming) + ' ms. ~';
Append(Result, StringOfChar(' ', Round((49 - Length(tmp)) div 2)) + tmp + #13#10);
Append(Result, '<===============================================>');
end;
(*
Auther: Officer Barbrady
*)
procedure PrintReport;
begin
WriteLn(TextReport);
end;
function OpenWebsite(site: string): Boolean;
begin
site := Trim(site);
Result := (Pos('.', site) > 0);
if Result then
OpenWebPage(site);
end;
function TimeStamp: string;
var
Hours, Minutes, Seconds, Milliseconds: Word;
tTSA: TStringArray;
i: Integer;
begin
DecodeTime(Now, Hours, Minutes, Seconds, Milliseconds);
if (Hours > 23) then
Hours := 0;
tTSA := [IntToStr(Hours), IntToStr(Minutes), IntToStr(Seconds), IntToStr(Milliseconds)];
for i := 0 to 2 do
if (StrToInt(tTSA[i]) < 10) then
tTSA[i] := ('0' + string(tTSA[i]));
while (Length(tTSA[3]) < 3) do
tTSA[3] := (string(tTSA[3]) + '0');
Result := string(tTSA[0] + ':' + tTSA[1] + ':' + tTSA[2] + ':' + tTSA[3]);
end;
procedure IncPoints(x: string);
begin
case Lowercase(x) of
'low': IncEx(points, POINTS_LOW);
'medium': IncEx(points, POINTS_MEDIUM);
'high': IncEx(points, POINTS_HIGH);
'very high': IncEx(points, POINTS_VERY_HIGH);
end;
end;
procedure NewThreat(var TTA: TThreatArray; line: Integer; threat: string; kind: (tk_Socket, tk_HTTP, tk_Web, tk_File, tk_Fishy, tk_Unhuman));
var
index, i, l: Integer;
begin
l := Length(TTA);
while (index < l) do
begin
if (line < TTA[index].line) then
Break;
Inc(index);
end;
SetLength(TTA, (l + 1));
if (l > index) then
for i := (l - 1) downto index do
TTA[(i + 1)] := TTA[i];
TTA[index].line := line;
TTA[index].threat := threat;
TTA[index].kind := kind;
case kind of
tk_Socket: Inc(SocketThreats);
tk_HTTP: Inc(HTTPThreats);
tk_Web: Inc(WebThreats);
tk_File: Inc(FileThreats);
tk_Fishy: Inc(FishyCode);
tk_Unhuman: Inc(UnhumanCode);
end;
end;
procedure TIADelete(var TIA: TIntegerArray; x: Integer);
var
i, h: Integer;
begin
h := High(TIA);
if ((x > h) or (x < 0)) then
Exit;
for i := x to (h - 1) do
TIA[i] := TIA[(i + 1)];
SetLength(TIA, h);
end;
procedure TIAInsert(var TIA: TIntegerArray; index: Integer; int: Integer);
var
i, l: Integer;
begin
l := Length(TIA);
SetLength(TIA, (l + 1));
if (index < 0) then
index := 0;
if (index > l) then
index := l;
if (l > index) then
for i := (l - 1) downto index do
TIA[(i + 1)] := Integer(TIA[i]);
TIA[index] := Integer(int);
end;
{==============================================================================]
Explanation: Returns string of all TSA items binded together. Places glue between the indexes.
[==============================================================================}
function TSAConcatEx(TSA: TStringArray; glue: string): string;
var
h, i: Integer;
begin
Result := '';
h := High(TSA);
if (h > -1) then
begin
for i := 0 to (h - 1) do
Result := (Result + string(TSA[i]) + string(glue));
Result := (Result + string(TSA[i]));
end;
end;
{==============================================================================]
Explanation: Explodes str with multiple separators/delimiters (d).
The importance order for d items is from left to right (=>).
So place the important ones first and then less important after those.
[==============================================================================}
function ExplodeMulti(d: TStringArray; str: string): TStringArray;
var
p, h, i, x, o, m, l, y, z: Integer;
begin
h := High(d);
if ((h > -1) and (str <> '')) then
begin
o := 1;
SetLength(Result, Length(str));
repeat
l := 0;
for x := 0 to h do
begin
p := Pos(d[x], str);
case (p < 1) of
True:
begin
z := High(d);
if ((x <= z) and (x > -1)) then
begin
for y := x to (z - 1) do
d[y] := d[(y + 1)];
SetLength(d, z);
end;
Dec(x);
Dec(h);
end;
False:
if ((l = 0) or (p < l)) then
begin
m := x;
l := p;
end;
end;
end;
if (l > 0) then
begin
Result[i] := Copy(str, 1, (l - 1));
Delete(str, 1, ((l + Length(d[m])) - 1));
Inc(i);
end else
Result[i] := Copy(str, 1, Length(str));
until (l = 0);
SetLength(Result, (i + 1));
end else
Result := [string(str)];
end;
{==============================================================================]
Explanation: Finds position from s items in str. Stores the ID of the found s item to index variable.
The importance order for d items is from left to right (=>).
So place the important ones first and then less important after those.
Contains field for offset.
[==============================================================================}
function PosMultiIDEx(s: TStringArray; str: string; var index: Integer; offset: Integer): Integer;
var
h, i, p, t: Integer;
begin
if (offset < 1) then
offset := 1;
Result := -1;
index := -1;
h := High(s);
if ((h > -1) and (str <> '')) then
begin
t := (Length(str) + 1);
Result := t;
for i := 0 to h do
begin
p := PosEx(s[i], str, offset);
if ((p > 0) and (p < Result)) then
begin
Result := p;
index := i;
end;
end;
if (Result = t) then
Result := 0;
end;
end;
function PosAll(s, str: string): TIntegerArray;
var
sL, strL, o, p, r: Integer;
begin
sL := Length(s);
strL := Length(str);
if (sL <= strL) then
begin
SetLength(Result, strL);
repeat
p := PosEx(s, str, (o + 1));
if (p > 0) then
begin
Result[r] := p;
o := p;
Inc(r);
end;
until (p <= 0);
end;
SetLength(Result, r);
end;
{==============================================================================]
Explanation: Indents str with spaces (just like the feature in SCAR, Ctrl+Shift+[I/U]).
shift is the amount of spaces. It can be positive value (indent), 0 (no change) or negative value (unindent).
[==============================================================================}
procedure Indentation(var str: string; shift: Integer);
var
d, tmp, nl: TStringArray;
p, h, i, x, o, m, l, y, z: Integer;
s: string;
begin
if ((str <> '') and (shift <> 0)) then
begin
d := [#13#10, #13, #10];
h := High(d);
o := 1;
SetLength(tmp, Length(str));
SetLength(nl, Length(str));
repeat
l := 0;
for x := 0 to h do
begin
p := Pos(d[x], str);
case (p < 1) of
True:
begin
z := High(d);
if ((x <= z) and (x > -1)) then
begin
for y := x to (z - 1) do
d[y] := d[(y + 1)];
SetLength(d, z);
end;
Dec(x);
Dec(h);
end;
False:
if ((l = 0) or (p < l)) then
begin
m := x;
l := p;
end;
end;
end;
if (l > 0) then
begin
tmp[i] := Copy(str, 1, (l - 1));
nl[i] := string(d[m]);
Delete(str, 1, ((l + Length(d[m])) - 1));
Inc(i);
end else
tmp[i] := Copy(str, 1, Length(str));
until (l = 0);
str := '';
SetLength(tmp, (i + 1));
SetLength(nl, i);
case (shift > 0) of
True:
begin
s := StringOfChar(' ', shift);
for x := 0 to i do
begin
str := (str + (s + tmp[x]));
if (x < i) then
str := (str + nl[x]);
end;
end;
False:
begin
shift := iAbs(shift);
for x := 0 to i do
begin
y := 0;
l := Length(tmp[x]);
while ((y < shift) and (y < l) and (tmp[x][(y + 1)] = ' ')) do
Inc(y);
if (y > 0) then
Delete(tmp[x], 1, y);
str := (str + tmp[x]);
if (x < i) then
str := (str + nl[x]);
end;
end;
end;
SetLength(tmp, 0);
SetLength(nl, 0);
end;
end;
function ToRange(minimum, maximum: Integer): TRange;
begin
Result.minimum := Integer(minimum);
Result.maximum := Integer(maximum);
end;
{==============================================================================]
Explanation: Returns true if int is in any range from ranges of TRA.
[==============================================================================}
function TRAContains(TRA: TRangeArray; int: Integer): Boolean;
var
h, i: Integer;
begin
h := High(TRA);
case (h > -1) of
True:
begin
for i := 0 to h do
if ((int >= TRA[i].minimum) and (int <= TRA[i].maximum)) then
Break;
Result := (i <= h);
end;
False: Result := False;
end;
end;
procedure TRAAppend(var TRA: TRangeArray; x: TRange);
var
aL: Integer;
begin
aL := (Length(TRA) + 1);
SetLength(TRA, aL);
TRA[(aL - 1)] := TRange(x);
end;
function TrackCaS(str: string; var comments, strings: TRangeArray): Boolean;
var
s, i, o, e, x, l, a, ls: Integer;
t: TStringArray;
begin
Result := False;
SetLength(comments, 0);
SetLength(strings, 0);
l := Length(str);
ls := -1;
if (l > 0) then
begin
o := 1;
t := ['//', '(*', '{', ''''];
repeat
s := PosMultiIDEx(t, str, i, o);
case (s <= ls) of
True: Exit;
False: ls := s;
end;
if (s > 0) then
begin
o := (s + 1);
a := 0;
case i of
0, 1, 2:
begin
case i of
0:
begin
e := PosMultiIDEx([#13#10, #13, #10], str, x, o);
if (x = 0) then
a := 1;
if (e = 0) then
e := l;
TRAAppend(comments, ToRange(s, e));
end;
1, 2:
begin
case i of
1:
begin
e := PosEx('*)', str, o);
a := 1;
end;
2: e := PosEx('}', str, o);
end;
if (e = 0) then
e := l;
TRAAppend(comments, ToRange(s, (e + a)));
end;
end;
end;
3:
begin
e := PosMultiIDEx([#13#10, #13, #10, ''''], str, x, o);
if (x = 0) then
a := 1;
case (e = 0) of
True:
begin
e := l;
TRAAppend(strings, ToRange(s, e));
end;
False:
case x of
0, 1, 2: TRAAppend(strings, ToRange(s, e));
3: TRAAppend(strings, ToRange(s, (e + a)));
end;
end;
end;
end;
o := ((e + 1) + a);
end;
until ((s = 0) or (x = -1) or (o > l));
end;
end;
{==============================================================================]
Explanation: Trims all TSA items.
[==============================================================================}
procedure TSATrim(var TSA: TStringArray);
var
h, i: Integer;
begin
h := High(TSA);
for i := 0 to h do
TSA[i] := Trim(TSA[i]);
end;
{==============================================================================]
Explanation: Returns all the positions by items from s array in str. Place s items in importance order (=>)
If overlap is set to true, strings can overlap.
(['aa'], 'baaaah', False) => [2,3,4]
(['aa'], 'baaaah', True) => [2,4]
[==============================================================================}
function PosAllMulti(s: TStringArray; str: string; overlap: Boolean): TIntegerArray;
var
h, l, p, o, x, i, t, r, y, d: Integer;
begin
h := High(s);
y := Length(str);
if ((y > 0) and (h > -1)) then
begin
SetLength(Result, y);
o := 1;
repeat
p := 0;
for x := 0 to h do
begin
t := PosEx(s[x], str, (l + o));
case (t < 1) of
True:
begin
for d := x to (h - 1) do
s[d] := s[(d + 1)];
SetLength(s, h);
Dec(x);
Dec(h);
end;
False:
if ((p = 0) or (t < p)) then
begin
p := t;
i := x;
end;
end;
end;
if (p > 0) then
begin
Result[r] := p;
Inc(r);
l := p;
if not overlap then
o := Length(s[i]);
end;
until (p <= 0);
end;
SetLength(Result, r);
end;
procedure FillStrRangeEx(var str: string; fillWith: Char; range: TRange; exceptions: TIntegerArray);
var
i, l, c: Integer;
begin
l := Length(str);
if ((l > 0) and not (range.minimum > range.maximum)) then
begin
if (range.minimum < 1) then
range.minimum := 1;
if (range.maximum > l) then
range.maximum := l;
if (range.minimum > l) then
Exit;
c := iAbs(range.maximum - range.minimum);
for i := range.minimum to range.maximum do
if not InIntArray(exceptions, i) then
str[i] := fillWith;
end;
end;
function FilterScriptData(data: string): string;
var
h, i, l: Integer;
newLines: TIntegerArray;
comments, strings: TRangeArray;
tmp: TStringArray;
begin
Result := string(data);
l := Length(Result);
displayScriptText := string(Result);
if (l > 0) then
begin
if (FILTER_STRINGS or FILTER_COMMENTS) then
begin
newLines := PosAllMulti([#13#10, #13, #10], Result, False);
TrackCaS(data, comments, strings);
h := High(comments);
if FILTER_COMMENTS then
for i := 0 to h do
begin
FillStrRangeEx(Result, '!', comments[i], newLines);
FillStrRangeEx(displayScriptText, COMMENT_FILTER, comments[i], newLines);
end;
h := High(strings);
if FILTER_COMMENTS then
for i := 0 to h do
begin
FillStrRangeEx(Result, '!', strings[i], newLines);
FillStrRangeEx(displayScriptText, STRING_FILTER, strings[i], newLines);
end;
SetLength(newLines, 0);
SetLength(comments, 0);
SetLength(strings, 0);
Result := ReplaceWrap(Result, '!', '', [rfReplaceAll]);
end;
tmp := ExplodeMulti([#13#10, #13, #10], Result);
TSATrim(tmp);
Result := TSAConcatEx(tmp, #13#10);
SetLength(tmp, 0);
tmp := ExplodeMulti([#13#10, #13, #10], displayScriptText);
displayScriptText := '';
h := High(tmp);
for i := 0 to h do
tmp[i] := (' ' + StringOfChar('0', (Length(IntToStr(h + 1)) - Length(IntToStr(i + 1)))) + IntToStr(i + 1) + '. ' + tmp[i]);
displayScriptText := TSAConcatEx(tmp, #13#10);
SetLength(tmp, 0);
end;
end;
{==============================================================================]
Explanation: Function for tracing findStr's from data.
Contains also custom fields for regexTags and regexStrs;
each tag performs a regex action, that is set to regexStrs, during the search.
[==============================================================================}
function TraceStrsEx(findStr: string; regexTags: array of Char; regexStrs: TStringArray; data: string; modifiers: set of TRegexModifier): TRangeArray;
var
re: TRegExp;
p, l, r, s, c, h, t: Integer;
q: string;
begin
l := Length(data);
s := Length(findStr);
if ((l > 0) and (s > 0)) then
begin
h := High(regexTags);
if (High(regexStrs) < h) then
SetLength(regexStrs, (h + 1));
SetLength(Result, l);
q := '.\+*?[^]$(){}=!<>|:-';
for c := h downto 0 do
begin
t := Pos(q, regexTags[c]);
if (t > 0) then
Delete(q, t, 1);
end;
for c := s downto 1 do
if (Pos(findStr[c], q) > 0) then
Insert('\', findStr, c);
for t := 0 to h do
findStr := Replace(findStr, regexTags[t], regexStrs[t], [rfReplaceAll]);
re := TRegExp.Create;
re.ModifierI := (rm_I in modifiers);
re.ModifierG := (rm_G in modifiers);
re.ModifierM := (rm_M in modifiers);
re.ModifierS := (rm_S in modifiers);
re.ModifierX := (rm_X in modifiers);
re.ModifierR := (rm_R in modifiers);
re.Expression := findStr;
re.InputString := data;
p := 1;
if re.ExecPos(p) then
repeat
if (re.Match[0] <> '') then
begin
p := (re.MatchPos[0] + 1);
Result[r].minimum := re.MatchPos[0];
Result[r].maximum := (Result[r].minimum + (re.MatchLen[0] - 1));
Inc(r);
end;
until not re.ExecPos(p);
SetLength(Result, r);
re.Free;
end else
SetLength(Result, 0);
end;
{==============================================================================]
Explanation: Returns all the positions of found/matching strings (findStr) in text.
Uses a set of TMatchMethod (methods) for string matching.
Contains field for offset.
If regex field is set as true, then this function searches for the regex you use.
[==============================================================================}
function FindEx(text, findStr: string; methods: TMatchMethods; offset: Integer; regex: Boolean): TIntegerArray;
var
rmArr: TRegexMatchArray;
rmArr2D: T2DRegexMatchArray;
sb, sa: string;
r, i, l, f, p, d, o, x, y, abL, abR, abX, abP, spA, spB, spH, spL, spI, spR, spD: Integer;
re: TRegExp;
ma, mb, a, s, ol: Boolean;
c: TIntegerArray;
t: T2DIntegerArray;
begin
l := Length(text);
f := Length(findStr);
if ((l > 0) and (f > 0) and (offset <= l)) then
begin
if (offset < 1) then
offset := 1;
if not regex then
begin
for i := f downto 1 do
if (Pos(findStr[i], '.\+*?[^]$(){}=!<>|:-') > 0) then
Insert('\', findStr, i);
SetLength(Result, l);
re := TRegExp.Create;
re.InputString := text;
re.Expression := findStr;
if (mmIgnoreCase in methods) then
re.ModifierI := True;
re.ModifierM := True;
a := (mmAll in methods);
re.ModifierG := (mmGreedyRegex in methods);
ol := (mmOverlap in methods);
if not ol then
o := (Length(findStr) - 1);
Inc(o);
p := offset;
while re.ExecPos(p) do
begin
Result[r] := re.MatchPos[0];
p := (Result[r] + o);
Inc(r);
end;
p := Offset;
re.Free;
SetLength(Result, r);
if ((r > 0) and (mmWholeWords in methods)) then
begin
s := (mmStrictWW in methods);
if not s then
c := [65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, // A-Z
97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, // a-z
48, 49, 50, 51, 52, 53, 54, 55, 56, 57]; // 0-9
case ol of
True:
begin
spH := High(Result);
if (spH > -1) then
begin
SetLength(t, (spH + 1));
t[0] := [Integer(Result[0])];
if (spH > 0) then
begin
spR := 1;
for spI := 1 to spH do
begin
for spA := 0 to (spR - 1) do
begin
spL := Length(t[spA]);
for spB := 0 to (spL - 1) do
begin
spD := IAbs(Result[spI] - t[spA][spB]);
if (spD <= f) then
begin
SetLength(t[spA], (spL + 1));
t[spA][spL] := Integer(Result[spI]);
Break;
end;
end;
if (spB < spL) then
Break;
end;
if (spA >= spR) then
begin
t[spR] := [Integer(Result[spI])];
Inc(spR);
end;
end;
end;
SetLength(t, spR);
spH := High(t);
for spI := spH downto 0 do
begin
spB := Low(t[spI]);
spA := High(t[spI]);
abX := 1;
abP := t[spI][spB];
abL := Length(text);
case ((abL > 0) and (abP > 1)) of
True:
begin
if ((abP - abX) < 1) then
abX := ((abP - abX) + (abX - 1));
if (abP > (abL + 1)) then
begin
abR := ((abP - abL) - 1);
abX := (abX - abR);
end;
sb := Copy(text, ((abP - abX) - abR), abX);
end;
False: sb := '';
end;
abX := 1;
abP := (t[spI][spA] + f);
abL := Length(text);
case ((abL > 0) and (abP <= abL)) of
True:
begin
if (abP < 1) then
begin
abX := (abX - iAbs(abP - 1));
abP := 1;
end;
if ((abX > 0) and ((abP + abX) > abL)) then
abX := (abX - (((abP + abX) - abL) - 1));
sa := Copy(text, abP, abX);
end;
False: sa := '';
end;
case s of
True:
begin
mb := (sb = '');
if not mb then
mb := ((sb = ' ') or (sb = #13#10) or (sb = #13) or (sb = #10));
ma := (sa = '');
if not ma then
ma := ((sa = ' ') or (sa = #13#10) or (sa = #13) or (sa = #10));
end;
False:
begin
mb := (sb = '');
if not mb then
mb := not InIntArray(c, Ord(sb[1]));
ma := (sa = '');
if not ma then
ma := not InIntArray(c, Ord(sa[1]));
end;
end;
if not (mb and ma) then
begin
for spD := spI to (spH - 1) do
t[spD] := t[(spD + 1)];
SetLength(t, spH);
Dec(spH);
end;
end;
spH := High(t);
if (spH > -1) then
begin
for spI := 0 to spH do
IncEx(spR, (High(t[spI]) + 1));
SetLength(Result, spR);
spR := 0;
for spI := 0 to spH do
begin
spL := High(t[spI]);
for spA := 0 to spL do
begin
Result[spR] := Integer(t[spI][spA]);
Inc(spR);
end;
end;
SetLength(Result, spR);
end else
SetLength(Result, 0);
end else
r := 0;
end;
False:
begin
for x := (r - 1) downto 0 do
begin
abX := 1;
abP := Result[x];
abL := Length(text);
case ((abL > 0) and (abP > 1)) of
True:
begin
if ((abP - abX) < 1) then
abX := ((abP - abX) + (abX - 1));
if (abP > (abL + 1)) then
begin
abR := ((abP - abL) - 1);
abX := (abX - abR);
end;
sb := Copy(text, ((abP - abX) - abR), abX);
end;
False: sb := '';
end;
abX := 1;
abP := (Result[x] + f);
abL := Length(text);
case ((abL > 0) and (abP <= abL)) of
True:
begin
if (abP < 1) then
begin
abX := (abX - iAbs(abP - 1));
abP := 1;
end;
if ((abX > 0) and ((abP + abX) > abL)) then
abX := (abX - (((abP + abX) - abL) - 1));
sa := Copy(text, abP, abX);
end;
False: sa := '';
end;
case s of
True:
begin
mb := (sb = '');
if not mb then
mb := ((sb = ' ') or (sb = #13#10) or (sb = #13) or (sb = #10));
ma := (sa = '');
if not ma then
ma := ((sa = ' ') or (sa = #13#10) or (sa = #13) or (sa = #10));
end;
False:
begin
mb := (sb = '');
if not mb then
mb := not InIntArray(c, Ord(sb[1]));
ma := (sa = '');
if not ma then
ma := not InIntArray(c, Ord(sa[1]));
end;
end;
if not (mb and ma) then
begin
y := (r - 1);
for d := x to (y - 1) do
Result[d] := Result[(d + 1)];
SetLength(Result, y);
Dec(r);
end;
end;
end;
end;
end;
if (not a and (r > 0)) then
SetLength(Result, 1);
end else
begin
SetLength(rmArr, l);
re := TRegExp.Create;
re.InputString := text;
re.Expression := findStr;
if (mmIgnoreCase in methods) then
re.ModifierI := True;
re.ModifierM := True;
a := (mmAll in methods);
re.ModifierG := (mmGreedyRegex in methods);
ol := (mmOverlap in methods);
p := offset;
while re.ExecPos(p) do
begin
rmArr[r].position := re.MatchPos[0];
rmArr[r].text := re.Match[0];
rmArr[r].size := re.MatchLen[0];
if ol then
p := (rmArr[r].position + 1)
else
p := (rmArr[r].position + rmArr[r].size);
Inc(r);
end;
p := Offset;
re.Free;
SetLength(rmArr, r);
if ((r > 0) and (mmWholeWords in methods)) then
begin
s := (mmStrictWW in methods);
if not s then
c := [65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, // A-Z
97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, // a-z
48, 49, 50, 51, 52, 53, 54, 55, 56, 57]; // 0-9
case ol of
True:
begin
spH := High(rmArr);
if (spH > -1) then
begin
SetLength(rmArr2D, (spH + 1));
rmArr2D[0] := [TRegexMatch(rmArr[0])];
if (spH > 0) then
begin
spR := 1;
for spI := 1 to spH do
begin
for spA := 0 to (spR - 1) do
begin
spL := Length(rmArr2D[spA]);
for spB := 0 to (spL - 1) do
begin
spD := IAbs(rmArr[spI].position - rmArr2D[spA][spB].position);
if (spD <= rmArr2D[spA][spB].size) then
begin
SetLength(rmArr2D[spA], (spL + 1));
rmArr2D[spA][spL] := TRegexMatch(rmArr[spI]);
Break;
end;
end;
if (spB < spL) then
Break;
end;
if (spA >= spR) then
begin
rmArr2D[spR] := [TRegexMatch(rmArr[spI])];
Inc(spR);
end;
end;
end;
SetLength(rmArr2D, spR);
spH := High(rmArr2D);
for spI := spH downto 0 do
begin
spB := Low(rmArr2D[spI]);
spA := High(rmArr2D[spI]);
abX := 1;
abP := rmArr2D[spI][spB].position;
abL := Length(text);
case ((abL > 0) and (abP > 1)) of
True:
begin
if ((abP - abX) < 1) then
abX := ((abP - abX) + (abX - 1));
if (abP > (abL + 1)) then
begin
abR := ((abP - abL) - 1);
abX := (abX - abR);
end;
sb := Copy(text, ((abP - abX) - abR), abX);
end;
False: sb := '';
end;
abX := 1;
abP := (rmArr2D[spI][spA].position + rmArr2D[spI][spA].size);
abL := Length(text);
case ((abL > 0) and (abP <= abL)) of
True:
begin
if (abP < 1) then
begin
abX := (abX - iAbs(abP - 1));
abP := 1;
end;
if ((abX > 0) and ((abP + abX) > abL)) then
abX := (abX - (((abP + abX) - abL) - 1));
sa := Copy(text, abP, abX);
end;
False: sa := '';
end;
case s of
True:
begin
mb := (sb = '');
if not mb then
mb := ((sb = ' ') or (sb = #13#10) or (sb = #13) or (sb = #10));
ma := (sa = '');
if not ma then
ma := ((sa = ' ') or (sa = #13#10) or (sa = #13) or (sa = #10));
end;
False:
begin
mb := (sb = '');
if not mb then
mb := not InIntArray(c, Ord(sb[1]));
ma := (sa = '');
if not ma then
ma := not InIntArray(c, Ord(sa[1]));
end;
end;
if not (mb and ma) then
begin
for spD := spI to (spH - 1) do
rmArr2D[spD] := rmArr2D[(spD + 1)];
SetLength(rmArr2D, spH);
Dec(spH);
end;
end;
spH := High(rmArr2D);
if (spH > -1) then
begin
for spI := 0 to spH do
IncEx(spR, (High(rmArr2D[spI]) + 1));
SetLength(rmArr, spR);
spR := 0;
for spI := 0 to spH do
begin
spL := High(rmArr2D[spI]);
for spA := 0 to spL do
begin
rmArr[spR] := TRegexMatch(rmArr2D[spI][spA]);
Inc(spR);
end;
end;
SetLength(rmArr, spR);
r := spR;
end else
SetLength(rmArr, 0);
end else
r := 0;
end;
False:
begin
for x := (r - 1) downto 0 do
begin
abX := 1;
abP := rmArr[x].position;
abL := Length(text);
case ((abL > 0) and (abP > 1)) of
True:
begin
if ((abP - abX) < 1) then
abX := ((abP - abX) + (abX - 1));
if (abP > (abL + 1)) then
begin
abR := ((abP - abL) - 1);
abX := (abX - abR);
end;
sb := Copy(text, ((abP - abX) - abR), abX);
end;
False: sb := '';
end;
abX := 1;
abP := (rmArr[x].position + rmArr[x].size);
abL := Length(text);
case ((abL > 0) and (abP <= abL)) of
True:
begin
if (abP < 1) then
begin
abX := (abX - iAbs(abP - 1));
abP := 1;
end;
if ((abX > 0) and ((abP + abX) > abL)) then
abX := (abX - (((abP + abX) - abL) - 1));
sa := Copy(text, abP, abX);
end;
False: sa := '';
end;
case s of
True:
begin
mb := (sb = '');
if not mb then
mb := ((sb = ' ') or (sb = #13#10) or (sb = #13) or (sb = #10));
ma := (sa = '');
if not ma then
ma := ((sa = ' ') or (sa = #13#10) or (sa = #13) or (sa = #10));
end;
False:
begin
mb := (sb = '');
if not mb then
mb := not InIntArray(c, Ord(sb[1]));
ma := (sa = '');
if not ma then
ma := not InIntArray(c, Ord(sa[1]));
end;
end;
if not (mb and ma) then
begin
y := (r - 1);
for d := x to (y - 1) do
rmArr[d] := rmArr[(d + 1)];
SetLength(rmArr, y);
Dec(r);
end;
end;
end;
end;
end;
r := Length(rmArr);
case (r > 0) of
True:
begin
if not a then
r := 1;
SetLength(Result, r);
for i := 0 to (r - 1) do
Result[i] := rmArr[i].position;
end;
False: SetLength(Result, 0);
end;
end;
end else
SetLength(Result, 0);
end;
function CountString(s, str: string): Integer;
begin
Result := Length(FindEx(str, s, [mmAll, mmIgnoreCase, mmWholeWords], 1, False));
end;
function CountStringEx(s, str: string; regex: Boolean): Integer;
begin
Result := Length(FindEx(str, s, [mmAll, mmIgnoreCase, mmWholeWords], 1, regex));
end;
function CountStringMulti(s: TStringArray; str: string): Integer;
var
tmp, all: TIntegerArray;
h, i, l, f, a: Integer;
begin
h := High(s);
if ((str <> '') and (h > -1)) then
begin
for i := 0 to h do
begin
tmp := FindEx(str, s[i], [mmAll, mmIgnoreCase, mmWholeWords], 1, False);
f := High(tmp);
if (h > -1) then
begin
l := Length(all);
SetLength(all, (l + (f + 1)));
for a := 0 to f do
all[(a + l)] := Integer(tmp[a]);
SetLength(tmp, 0);
end;
end;
ClearSameIntegers(all);
Result := Length(all);
SetLength(all, 0);
end;
end;
function CountStringMultiEx(s: TStringArray; str: string; regex: Boolean): Integer;
var
tmp, all: TIntegerArray;
h, i, l, f, a: Integer;
begin
h := High(s);
if ((str <> '') and (h > -1)) then
begin
for i := 0 to h do
begin
tmp := FindEx(str, s[i], [mmAll, mmIgnoreCase, mmWholeWords], 1, regex);
f := High(tmp);
if (h > -1) then
begin
l := Length(all);
SetLength(all, (l + (f + 1)));
for a := 0 to f do
all[(a + l)] := Integer(tmp[a]);
SetLength(tmp, 0);
end;
end;
ClearSameIntegers(all);
Result := Length(all);
SetLength(all, 0);
end;
end;
function PositionToLine(position: Integer): Integer;
var
h: Integer;
begin
Result := 1;
h := High(linePositions);
if (h > -1) then
case (h > 0) of
True:
for Result := 1 to (h + 1) do
if (position < linePositions[(Result - 1)]) then
Break;
False:
if (position >= linePositions[0]) then
Result := 2;
end;
Dec(Result);
end;
procedure AddMessage(var msgs: string; msg: string);
begin
case (msgs <> '') of
True: msgs := (msgs + #13#10 + msg);
False: msgs := msg;
end;
end;
procedure FilterFalsePositives(var positions: TIntegerArray);
var
h, i: Integer;
begin
h := High(positions);
if ((h > -1) and (High(falsePositives) > -1)) then
for i := h downto 0 do
if TRAContains(falsePositives, positions[i]) then
TIADelete(positions, i);
end;
procedure FindSocketThreats;
var
tr, st: TStringArray;
h, i, x, t, m, l: Integer;
tmp: TIntegerArray;
es, ts, str: string;
begin
msgHTTP := '';
Inc(currentStep);
ts := TimeStamp;
t := GetSystemTime;
tmp := FindEx(filteredScriptText, 'createsocket', [mmAll, mmIgnoreCase, mmWholeWords], 1, True);
FilterFalsePositives(tmp);
str := (str + (' ????<' + ts + '> Scan for CreateSocket [' + IntToStr(GetSystemTime - t) + ' ms.]') + #13#10);
h := High(tmp);
if (h > -1) then
begin
if (h > 0) then
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREATS:') + #13#10)
else
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREAT:') + #13#10);
for i := 0 to h do
begin
l := PositionToLine(tmp[i]);
NewThreat(threats, l, 'CreateSocket', tk_Socket);
str := (str + (' ????????<' + TimeStamp + '> Found CreateSocket @ line ' + IntToStr(l) + '!') + #13#10);
end;
AddMessage(msgSocket, (' Found "CreateSocket" [Risk level: VERY HIGH]'));
IncPoints('VERY HIGH');
end;
tr := ['VERY HIGH', 'VERY HIGH', 'HIGH', 'HIGH', 'HIGH', 'HIGH', 'HIGH'];
st := ['ConnectSocket', 'SendSocket', 'RecvSocket', 'RecvSocketStr', 'RecvSocketEx', 'BindSocket', 'SocketInfo'];
for x := 0 to High(st) do
begin
es := TimeStamp;
m := GetSystemTime;
tmp := FindEx(filteredScriptText, ('(\W)' + Lowercase(st[x]) + ReplaceWrap(' (\()', ' ', '(\s*)', [rfReplaceAll])), [mmAll, mmIgnoreCase, mmOverlap], 1, True);
FilterFalsePositives(tmp);
str := (str + (' ????<' + es + '> Scan for ' + (st[x] + '(*)') + ' [' + IntToStr(GetSystemTime - m) + ' ms.]') + #13#10);
h := High(tmp);
if (h > -1) then
begin
if (h > 0) then
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREATS:') + #13#10)
else
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREAT:') + #13#10);
for i := 0 to h do
begin
l := PositionToLine(tmp[i]);
NewThreat(threats, PositionToLine(tmp[i]), (st[x] + '(*)'), tk_Socket);
str := (str + (' ????????<' + TimeStamp + '> Found ' + (st[x] + '(*)') + ' @ line ' + IntToStr(l) + '!') + #13#10);
end;
AddMessage(msgSocket, (' Found "' + st[x] + '" [Risk level: ' + tr[x] + ']'));
IncPoints(tr[x]);
end;
SetLength(tmp, 0);
end;
if (steps <> '') then
steps := (steps + ' ?' + #13#10);
steps := (steps + (' ??<' + ts + '> Step ' + IntToStr(currentStep) + '/' + IntToStr(totalSteps) + ' - Socket Threats [' + IntToStr(GetSystemTime - t) + ' ms.]') + #13#10 + str);
str := '';
SetLength(st, 0);
SetLength(tr, 0);
end;
(*
Auther: Officer Barbrady
*)
procedure FindHTTPThreats;
var
tr, ht: TStringArray;
h, i, x, t, m, l: Integer;
tmp: TIntegerArray;
es, ts, str: string;
begin
msgHTTP := '';
Inc(currentStep);
tr := ['VERY HIGH', 'HIGH', 'HIGH', 'HIGH', 'MEDIUM', 'MEDIUM', 'MEDIUM', 'HIGH', 'HIGH'];
ht := ['AddPostVariable', 'GetPage', 'PostHTTPPage', 'PostHTTPPageEx', 'GetRawHeaders', 'SetHTTPUserAgent', 'GetHTTPPage', 'InitializeHTTPClient', 'InitializeHTTPClientWrap'];
ts := TimeStamp;
t := GetSystemTime;
for x := 0 to High(ht) do
begin
es := TimeStamp;
m := GetSystemTime;
tmp := FindEx(filteredScriptText, ('(\W)' + Lowercase(ht[x]) + ReplaceWrap(' (\()', ' ', '(\s*)', [rfReplaceAll])), [mmAll, mmIgnoreCase, mmOverlap], 1, True);
FilterFalsePositives(tmp);
str := (str + (' ????<' + es + '> Scan for ' + (ht[x] + '(*)') + ' [' + IntToStr(GetSystemTime - m) + ' ms.]') + #13#10);
h := High(tmp);
if (h > -1) then
begin
if (h > 0) then
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREATS:') + #13#10)
else
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREAT:') + #13#10);
for i := 0 to h do
begin
l := PositionToLine(tmp[i]);
NewThreat(threats, l, (ht[x] + '(*)'), tk_HTTP);
str := (str + (' ????????<' + TimeStamp + '> Found ' + (ht[x] + '(*)') + ' @ line ' + IntToStr(l) + '!') + #13#10);
end;
AddMessage(msgHTTP, (' Found "' + ht[x] + '" [Risk level: ' + tr[x] + ']'));
IncPoints(tr[x]);
end;
SetLength(tmp, 0);
end;
if (steps <> '') then
steps := (steps + ' ?' + #13#10);
steps := (steps + (' ??<' + ts + '> Step ' + IntToStr(currentStep) + '/' + IntToStr(totalSteps) + ' - HTTP Threats [' + IntToStr(GetSystemTime - t) + ' ms.]') + #13#10 + str);
str := '';
SetLength(ht, 0);
SetLength(tr, 0);
end;
(*
Auther: Officer Barbrady
*)
procedure FindWebThreats;
var
h, i, t, l: Integer;
tmp: TIntegerArray;
ts, str: string;
begin
msgWeb := '';
Inc(currentStep);
ts := TimeStamp;
t := GetSystemTime;
tmp := FindEx(filteredScriptText, ('(\W)openwebpage' + ReplaceWrap(' (\()', ' ', '(\s*)', [rfReplaceAll])), [mmAll, mmIgnoreCase, mmOverlap], 1, True);
FilterFalsePositives(tmp);
str := (str + (' ????<' + ts + '> Scan for OpenWebPage(*) [' + IntToStr(GetSystemTime - t) + ' ms.]') + #13#10);
h := High(tmp);
if (h > -1) then
begin
if (h > 0) then
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREATS:') + #13#10)
else
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREAT:') + #13#10);
for i := 0 to h do
begin
l := PositionToLine(tmp[i]);
NewThreat(threats, PositionToLine(tmp[i]), 'OpenWebPage(*)', tk_Web);
str := (str + (' ????????<' + TimeStamp + '> Found OpenWebPage(*) @ line ' + IntToStr(l) + '!') + #13#10);
end;
AddMessage(msgWeb, ' Found "OpenWebPage" [Risk level: HIGH]');
IncPoints('HIGH');
SetLength(tmp, 0);
end;
if (steps <> '') then
steps := (steps + ' ?' + #13#10);
steps := (steps + (' ??<' + ts + '> Step ' + IntToStr(currentStep) + '/' + IntToStr(totalSteps) + ' - Web Threats [' + IntToStr(GetSystemTime - t) + ' ms.]') + #13#10 + str);
str := '';
end;
procedure FindFileThreats;
var
tr, ft: TStringArray;
h, i, x, t, m, l: Integer;
tmp: TIntegerArray;
es, ts, str: string;
begin
msgFile := '';
Inc(currentStep);
tr := ['HIGH', 'HIGH', 'VERY HIGH', 'MEDIUM', 'HIGH', 'MEDIUM', 'MEDIUM', 'HIGH', 'HIGH', 'MEDIUM', 'MEDIUM', 'VERY HIGH', 'VERY HIGH', 'HIGH', 'LOW', 'VERY HIGH'];
ft := ['CreateFile', 'OpenFile', 'RewriteFile', 'ReadFileString', 'WriteFileString', 'DirectoryExists', 'FileExists', 'CreateDirectory', 'ForceDirectories', 'GetFiles', 'GetDirectories', 'DeleteFile', 'RenameFile', 'WriteINI', 'ReadINI', 'DeleteINI'];
ts := TimeStamp;
t := GetSystemTime;
for x := 0 to High(ft) do
begin
es := TimeStamp;
m := GetSystemTime;
tmp := FindEx(filteredScriptText, ('(\W)' + Lowercase(ft[x]) + ReplaceWrap(' (\()', ' ', '(\s*)', [rfReplaceAll])), [mmAll, mmIgnoreCase, mmOverlap], 1, True);
FilterFalsePositives(tmp);
str := (str + (' ????<' + es + '> Scan for ' + (ft[x] + '(*)') + ' [' + IntToStr(GetSystemTime - m) + ' ms.]') + #13#10);
h := High(tmp);
if (h > -1) then
begin
if (h > 0) then
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREATS:') + #13#10)
else
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREAT:') + #13#10);
for i := 0 to h do
begin
l := PositionToLine(tmp[i]);
NewThreat(threats, l, (ft[x] + '(*)'), tk_File);
str := (str + (' ????????<' + TimeStamp + '> Found ' + (ft[x] + '(*)') + ' @ line ' + IntToStr(l) + '!') + #13#10);
end;
AddMessage(msgFile, (' Found "' + ft[x] + '" [Risk level: ' + tr[x] + ']'));
IncPoints(tr[x]);
end;
SetLength(tmp, 0);
end;
if (steps <> '') then
steps := (steps + ' ?' + #13#10);
steps := (steps + (' ??<' + ts + '> Step ' + IntToStr(currentStep) + '/' + IntToStr(totalSteps) + ' - File Threats [' + IntToStr(GetSystemTime - t) + ' ms.]') + #13#10 + str);
str := '';
SetLength(ft, 0);
SetLength(tr, 0);
end;
(*
Auther: Officer Barbrady
*)
procedure FindBadCode;
var
h, i, x, t, m, l: Integer;
tr, ac, bc: TStringArray;
tmp: TIntegerArray;
ts, es, p, s, str: string;
begin
msgFishy := '';
Inc(currentStep);
tr := ['MEDIUM', 'VERY HIGH', 'HIGH'];
ac := ['Name', 'Pass', 'Pin'];
ts := TimeStamp;
t := GetSystemTime;
if STRICT_PLAYERS_INFO_DETECTION then
p := 'Players[*].';
for x := 0 to High(ac) do
begin
es := TimeStamp;
m := GetSystemTime;
case STRICT_PLAYERS_INFO_DETECTION of
True: tmp := FindEx(filteredScriptText, ReplaceWrap('ToStr (\() players (\[) [a-zA-Z0-9]* (\]) (\))', ' ', '(\s*)', [rfReplaceAll]), [mmAll, mmIgnoreCase, mmWholeWords], 1, True);
False: tmp := FindEx(filteredScriptText, ac[x], [mmAll, mmIgnoreCase, mmWholeWords], 1, True);
end;
FilterFalsePositives(tmp);
str := (str + (' ????<' + es + '> Scan for ' + (p + ac[x]) + ' [' + IntToStr(GetSystemTime - m) + ' ms.]') + #13#10);
h := High(tmp);
if (h > 0) then
begin
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREATS:') + #13#10);
for i := 0 to h do
begin
l := PositionToLine(tmp[i]);
NewThreat(threats, l, (p + ac[x]), tk_Fishy);
str := (str + (' ????????<' + TimeStamp + '> Found ' + (p + ac[x]) + ' @ line ' + IntToStr(l) + '!') + #13#10);
end;
AddMessage(msgFishy, (' The variable "' + (p + ac[x]) + '" is used more then once [Risk level: ' + tr[x] + ']'));
IncPoints(tr[x]);
end;
SetLength(tmp, 0);
end;
es := TimeStamp;
m := GetSystemTime;
tmp := FindEx(filteredScriptText, ReplaceWrap('ToStr (\() players (\[) [a-zA-Z0-9]* (\]) (\))', ' ', '(\s*)', [rfReplaceAll]), [mmAll, mmIgnoreCase, mmWholeWords], 1, True);
FilterFalsePositives(tmp);
str := (str + (' ????<' + es + '> Scan for ToStr(Players[*]) [' + IntToStr(GetSystemTime - m) + ' ms.]') + #13#10);
h := High(tmp);
if (h > -1) then
begin
if (h > 0) then
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREATS:') + #13#10)
else
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREAT:') + #13#10);
for i := 0 to h do
begin
l := PositionToLine(tmp[i]);
NewThreat(threats, l, 'ToStr(Players[*])', tk_Fishy);
str := (str + (' ????????<' + TimeStamp + '> Found ToStr(Players[*]) @ line ' + IntToStr(l) + '!') + #13#10);
end;
AddMessage(msgFishy, ' Player data sent to ToStr() [Risk level: VERY HIGH]');
IncPoints('VERY HIGH');
SetLength(tmp, 0);
end;
tr := ['MEDIUM', 'MEDIUM', 'MEDIUM', 'MEDIUM', 'HIGH', 'HIGH', 'MEDIUM', 'MEDIUM'];
ac := ['TradeScreen', 'SomeoneTrades', 'GetTradersName', 'TradeScreenName', 'AcceptTrade', 'Accept', 'Waiting', 'PlayerAccepted'];
ts := TimeStamp;
t := GetSystemTime;
for x := 0 to High(ac) do
begin
es := TimeStamp;
m := GetSystemTime;
tmp := FindEx(filteredScriptText, ac[x], [mmAll, mmIgnoreCase, mmWholeWords], 1, True);
FilterFalsePositives(tmp);
str := (str + (' ????<' + es + '> Scan for ' + (p + ac[x]) + ' [' + IntToStr(GetSystemTime - m) + ' ms.]') + #13#10);
h := High(tmp);
if (h > -1) then
begin
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREATS:') + #13#10);
for i := 0 to h do
begin
l := PositionToLine(tmp[i]);
NewThreat(threats, l, (p + ac[x]), tk_Fishy);
str := (str + (' ????????<' + TimeStamp + '> Found ' + ac[x] + ' @ line ' + IntToStr(l) + '!') + #13#10);
end;
AddMessage(msgFishy, (' Picked up trading activity command "' + ac[x] + '" (UNUSUAL) [Risk level: ' + tr[x] + ']'));
IncPoints(tr[x]);
end;
SetLength(tmp, 0);
end;
if (steps <> '') then
steps := (steps + ' ?' + #13#10);
steps := (steps + (' ??<' + ts + '> Step ' + IntToStr(currentStep) + '/' + IntToStr(totalSteps) + ' - Fishy Code [' + IntToStr(GetSystemTime - t) + ' ms.]') + #13#10 + str);
str := '';
SetLength(ac, 0);
msgUnhuman := '';
Inc(currentStep);
t := GetSystemTime;
tr := ['LOW', 'LOW'];
bc := ['(\W)mmouse (\() x , y , 1 , 1 (\))', '(\W)mouse (\() x , y , 1 , 1 ,(.*?)(\))'];
for x := 0 to 1 do
begin
case x of
0: s := 'MMouse(x, y, 1, 1)';
1: s := 'Mouse(x, y, 1, 1, *)';
end;
es := TimeStamp;
tmp := FindEx(filteredScriptText, ReplaceWrap(bc[x], ' ', '(\s*)', [rfReplaceAll]), [mmAll, mmIgnoreCase], 1, True);
FilterFalsePositives(tmp);
str := (str + (' ????<' + es + '> Scan for ' + s + ' [' + IntToStr(GetSystemTime - m) + ' ms.]') + #13#10);
h := High(tmp);
if (h > -1) then
begin
if (h > 0) then
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREATS:') + #13#10)
else
str := (str + (' ??????<' + TimeStamp + '> DETECTED ' + IntToStr(h + 1) + ' THREATS:') + #13#10);
for i := 0 to h do
begin
l := PositionToLine(tmp[i]);
NewThreat(threats, l, s, tk_Unhuman);
str := (str + (' ????????<' + TimeStamp + '> Found ' + s + ' @ line ' + IntToStr(l) + '!') + #13#10);
end;
AddMessage(msgUnhuman, (' Found "' + s + '" (potential ban) [Risk level: ' + tr[x] + ']'));
IncPoints(tr[x]);
SetLength(tmp, 0);
end;
end;
es := TimeStamp;
m := GetSystemTime;
tmp := FindEx(filteredScriptText, ReplaceWrap('((\W)random (\()|(\W)randomrange (\())', ' ', '(\s*)', [rfReplaceAll]), [mmAll, mmIgnoreCase], 1, True);
FilterFalsePositives(tmp);
str := (str + (' ????<' + es + '> Scan for Random[Range](*) [' + IntToStr(GetSystemTime - m) + ' ms.]') + #13#10);
h := High(tmp);
case (h = -1) of
True:
begin
str := (str + (' ??????<' + TimeStamp + '> DETECTED 1 THREAT:') + #13#10);
NewThreat(threats, -1, 'Random[Range](*)', tk_Unhuman);
str := (str + (' ????????<' + TimeStamp + '> Could not find Random[Range](*) @ ANY line!') + #13#10);
AddMessage(msgUnhuman, ' Couldn''t find any randomness in script (potential ban) [Risk level: MEDIUM]');
IncPoints('MEDIUM');
end;
False: SetLength(tmp, 0);
end;
if (steps <> '') then
steps := (steps + ' ?' + #13#10);
steps := (steps + (' ??<' + ts + '> Step ' + IntToStr(currentStep) + '/' + IntToStr(totalSteps) + ' - Unhuman/Abnormal Code [' + IntToStr(GetSystemTime - t) + ' ms.]') + #13#10 + str);
str := '';
SetLength(bc, 0);
SetLength(tr, 0);
end;
procedure TrackFalsePositives;
var
h, x, i, l: Integer;
a: array of TRangeArray;
begin
SetLength(falsePositives, 0);
a := [TraceStrsEx('font . name', [' '], ['(\s*)'], filteredScriptText, [rm_I]),
TraceStrsEx(' inpin @', [' ', '@'], ['(\s*)', '(\()(\s*)players(\s*)(\[)(\s*)\w+(\s*)(\])(\s*)(\.)(\s*)pin(\s*)(\))'], filteredScriptText, [rm_I])];
h := High(a);
for i := 0 to h do
begin
l := Length(a[i]);
for x := 0 to (l - 1) do
TRAAppend(falsePositives, a[i][x]);
end;
end;
(*
Auther: Officer Barbrady
*)
procedure Scan;
var
tmp: string;
begin
if SOCKET_SCAN then
Inc(totalSteps);
if HTTP_SCAN then
Inc(totalSteps);
if WEB_SCAN then
Inc(totalSteps);
if FILE_SCAN then
Inc(totalSteps);
if CODE_SCAN then
IncEx(totalSteps, 2);
scanTimer := GetSystemTime;
TrackFalsePositives;
if SOCKET_SCAN then
FindSocketThreats;
if HTTP_SCAN then
FindHTTPThreats;
if WEB_SCAN then
FindWebThreats;
if FILE_SCAN then
FindFileThreats;
if CODE_SCAN then
FindBadCode;
steps := (' ??????????????????????????????????????????????? ' + #13#10 + steps + ' ??????????????????????????????????????????????? ' + #13#10);
tmp := '--- Scanning ' + IntToStr(Length(linePositions)) + ' lines took ' + IntToStr(GetSystemTime - scanTimer) + ' ms. ---';
steps := (steps + StringOfChar(' ', Round((49 - Length(tmp)) div 2)) + tmp);
PrintReport;
end;
procedure OpenMyProfile(Sender: TObject);
var
p: string;
begin
case Sender of
HelpMenuItems[0]: p := 'http://villavu.com/forum/private.php?do=newpm&u=63718'; // Officer Barbrady
HelpMenuItems[1]: p := 'http://villavu.com/forum/private.php?do=newpm&u=31'; // Janilabo
end;
if (p <> '') then
OpenWebsite(p);
end;
procedure About(Sender: TObject);
begin
WriteLn('=====================About=====================');
WriteLn('This exension is for scanning scripts to see if they contain any type of malicious material.');
WriteLn('===============================================');
WriteLn(' ');
end;
procedure Development(Sender: TObject);
begin
WriteLn('==================Development==================');
WriteLn(' Officer Barbrady [Main Developer]');
WriteLn(' - Graphical User Interface');
WriteLn(' - Extension Implentation');
WriteLn(' Janilabo [Developer]');
WriteLn(' - String Functions');
WriteLn(' - Core Features');
WriteLn(' Rich [Contributor]');
WriteLn(' - Automatical checks for Scan Settings');
WriteLn(' Brandon [Contributor]');
WriteLn(' - Improvement suggestions (Socket detection!)');
WriteLn('===============================================');
WriteLn(' ');
end;
procedure OpenThread(Sender: TObject);
begin
OpenWebsite('http://villavu.com/forum/showthread.php?t=103408');
end;
(*
Auther: Officer Barbrady
*)
procedure Update(Sender: TObject);
var
latestVersion: Extended;
str: string;
begin
WriteLn('Getting update information, please wait.');
WriteLn('This step may take a couple seconds!');
str := GetPage('http://villavu.com/forum/showthread.php?t=103408');
latestVersion := StrToFloatDef(Between('autoupdate', 'abcdef', str), -1);
case (latestVersion > -1) of
True:
begin
WriteLn('Current Version: ' + FloatToStr(VERSION) + ' | Latest Version: ' + FloatToStr(latestVersion));
case (VERSION = latestVersion) of
False:
case (VERSION < latestVersion) of
True:
begin
WriteLn('You dont have the latest version, you can download the latest version from the thread.');
OpenWebsite('http://villavu.com/forum/showthread.php?t=103408');
end;
False: WriteLn('Looks like your version is newer than the latest version - YAY!');
end;
True: WriteLn('Your version is up to date!');
end;
end;
False: WriteLn('Failed to check the latest version... Connection problems?');
end;
end;
(*
Auther: Officer Barbrady
*)
procedure SaveFormInfo;
var
tmp: TStringArray;
begin
scanTiming := GetSystemTime;
steps := '';
SocketThreats := 0;
HTTPThreats := 0;
WebThreats := 0;
FileThreats := 0;
UnhumanCode := 0;
FishyCode := 0;
points := 0;
currentStep := 0;
totalSteps := 0;
SetLength(threats, 0);
SetLength(falsePositives, 0);
SetLength(linePositions, 0);
msgSocket := '';
msgHTTP := '';
msgWeb := '';
msgFile := '';
msgUnhuman := '';
msgFishy := '';
originalScriptText := '';
filteredScriptText := '';
displayScriptText := '';
DsgnForm.ModalResult := mrOk;
tmp := ExplodeMulti([#13#10, #13, #10], ScriptEdit.Text);
originalScriptText := TSAConcatEx(tmp, #13#10);
SetLength(tmp, 0);
filteredScriptText := FilterScriptData(originalScriptText);
Indentation(filteredScriptText, 1);
linePositions := PosAll(#13#10, filteredScriptText);
TIAInsert(linePositions, 0, 1);
HTTP_SCAN := CheckBoxs[0].Checked;
WEB_SCAN := CheckBoxs[1].Checked;
CODE_SCAN := CheckBoxs[2].Checked;
DEBUG_FILTERED_SCRIPT := CheckBoxs[3].Checked;
FILTER_COMMENTS := CheckBoxs[4].Checked;
FILTER_STRINGS := CheckBoxs[5].Checked;
SOCKET_SCAN := CheckBoxs[6].Checked;
FILE_SCAN := CheckBoxs[7].Checked;
pressed := True;
Scan;
// DsgnForm.Close;
end;
procedure UpdateCB(Sender: TObject);
begin
case Sender of
CheckBoxs[0]: HTTP_SCAN := CheckBoxs[0].Checked;
CheckBoxs[1]: WEB_SCAN := CheckBoxs[1].Checked;
CheckBoxs[2]: CODE_SCAN := CheckBoxs[2].Checked;
CheckBoxs[3]: DEBUG_FILTERED_SCRIPT := CheckBoxs[3].Checked;
CheckBoxs[4]: FILTER_COMMENTS := CheckBoxs[4].Checked;
CheckBoxs[5]: FILTER_STRINGS := CheckBoxs[5].Checked;
CheckBoxs[6]: SOCKET_SCAN := CheckBoxs[6].Checked;
CheckBoxs[7]: FILE_SCAN := CheckBoxs[7].Checked;
end;
end;
Procedure ShowResults(Sender: TObject);
begin
Resultsform.SHOW;
Resultsform.SetFocus;
SaveFormInfo;
end;
Procedure InitResultsForm;
var
i, h: Integer;
Strings: TStringArray;
Points: TPointArray;
Parents: TIntegerArray;
begin
ResultsForm:=TForm.Create(nil);
ResultsForm.Caption:='Scan Results';
ResultsForm.Left:=200;
ResultsForm.Top:=200;
ResultsForm.Width:=580;
ResultsForm.Height:=350;
ResultsForm.Font.Name:=default;
ResultsForm.Font.Color:=clDefault;
ResultsForm.Font.Size:=0;
P2 := TPageControl.Create(ResultsForm);
P2.Parent := ResultsForm;
P2.SetBounds(0, 0, 750, 460);
Strings := ['Scan Steps','Lines with threats','Messages','Scan Results','Filtered script']
for i:=0 to high(Resulttabs) do
begin
Resulttabs[i] := TTabSheet.Create(P2);
Resulttabs[i].Caption := Strings[i];
Resulttabs[i].Visible := True;
Resulttabs[i].PageControl := P2;
end;
for i := 0 to high(debugboxes) do
begin
debugboxes[i] := TMemo.Create(ResultsForm);
debugboxes[i].Parent := P2.Pages[i];
debugboxes[i].Left := 10;
debugboxes[i].Top := 20;
debugboxes[i].Width := 530;
debugboxes[i].Height := 270;
debugboxes[i].Font.Name := 'Courier New';
debugboxes[i].Font.Size := 10;
debugboxes[i].WordWrap := False;
debugboxes[i].ScrollBars := ssboth;
end;
end;
(*
Auther: Officer Barbrady
Description: Starts the form.
*)
procedure InitForm;
var
i, h: Integer;
Strings: TStringArray;
Points: TPointArray;
Parents: TIntegerArray;
begin
DsgnForm := TForm.Create(nil);
with DsgnForm do
begin
Caption := 'Simba Script Scanner v' + ToStr(VERSION) + ' by Officer Barbrady and Janilabo';
Left := 900;
Top := 395;
Width := 750;
Height := 460;
Font.Name := DEFAULT;
end;
P := TPageControl.Create(DsgnForm);
P.Parent := DsgnForm;
P.SetBounds(0, 0, 750, 460);
Strings := ['Script Input','Scan Settings']
for i:=0 to high(tabs) do
begin
Tabs[i] := TTabSheet.Create(P);
Tabs[i].Caption := Strings[i];
Tabs[i].Visible := True;
Tabs[i].PageControl := P;
end;
ScriptEdit := TMemo.Create(DsgnForm);
with ScriptEdit do
begin
Parent := P.Pages[0];
Left := 20;
Top := 20;
Width := 700;
Height := 330;
Font.Name := 'Courier New';
Font.Size := 10;
WordWrap := True;
Lines.Add('Paste script into this box, it will scan for suspicious/malicious lines of code');
ScrollBars := ssBoth;
end;
Strings := ['Scan', 'Update'];
Points := [Point(175, 380), Point(400, 380)];
h := High(Buttons);
for i := 0 to h do
begin
Buttons[i] := TButton.Create(DsgnForm);
Buttons[i].Parent := P.Pages[0];
Buttons[i].Caption := Strings[i];
Buttons[i].Left := Points[i].X;
Buttons[i].Top := Points[i].Y;
Buttons[i].Width := 150;
Buttons[i].Height := 25;
Buttons[i].Font.Size := 12;
case i of
0: Buttons[i].OnClick := @ShowResults;
1: Buttons[1].OnClick := [MENTION=129311]Update[/MENTION];
end;
end;
Strings := ['Scan for HTTP Threats', 'Scan for Web Threats', 'Scan for Bad Code','Debug Filtered Script', 'Filter Comments', 'Filter Strings', 'Scan for Socket Threats', 'Scan for File Threats'];
Points := [Point(200, 100), Point(400, 100), Point(400, 160), Point(200, 160), Point(200, 220), Point(400, 220), Point(200, 280), Point(400, 280)];
h := High(CheckBoxs);
for i := 0 to h do
begin
CheckBoxs[i] := TCheckBox.Create(DsgnForm);
CheckBoxs[i].Parent := P.Pages[1];
CheckBoxs[i].Left := Points[i].X;
CheckBoxs[i].Top := Points[i].Y;
CheckBoxs[i].Width := 97;
CheckBoxs[i].Caption := Strings[i];
CheckBoxs[i].Checked := True;
CheckBoxs[i].OnClick := [MENTION=129311]Update[/MENTION]CB;
end;
HTTP_SCAN := CheckBoxs[0].Checked;
WEB_SCAN := CheckBoxs[1].Checked;
CODE_SCAN := CheckBoxs[2].Checked;
DEBUG_FILTERED_SCRIPT := CheckBoxs[3].Checked;
FILTER_COMMENTS := CheckBoxs[4].Checked;
FILTER_STRINGS := CheckBoxs[5].Checked;
SOCKET_SCAN := CheckBoxs[6].Checked;
FILE_SCAN := CheckBoxs[7].Checked;
end;
(*
Auther: Officer Barbrady
*)
procedure Start(Sender: TObject);
begin
try
InitForm;
InitResultsForm;
DsgnForm.ShowModal;
if pressed then Scan;
finally
steps := '';
totalSteps := 0;
currentStep := 0;
SetLength(threats, 0);
SetLength(falsePositives, 0);
originalScriptText := '';
filteredScriptText := '';
displayScriptText := '';
SetLength(linePositions, 0);
SocketThreats := 0;
HTTPThreats := 0;
WebThreats := 0;
FileThreats := 0;
UnhumanCode := 0;
FishyCode := 0;
points := 0;
msgSocket := '';
msgHTTP := '';
msgWeb := '';
msgFile := '';
msgFishy := '';
msgUnhuman := '';
except
WriteLn('Error Showing Form');
end;
end;
procedure Init;
var
h, i: Integer;
Strings: TStringArray;
begin;
Simba_Menu := TMenuItem.Create(Simba_MainMenu);
Simba_Menu.Caption := 'SSS';
Simba_MainMenu.Items.Add(Simba_Menu);
Strings := ['Scan', 'Update', 'About', 'Help', 'Script Thread', 'Development'];
h := High(MenuItems);
for i := 0 to h do
begin
MenuItems[i] := TMenuItem.Create(Simba_Menu);
MenuItems[i].Caption := Strings[i]
case i of
0: MenuItems[i].OnClick := [MENTION=30864]start[/MENTION];
1: MenuItems[i].OnClick := [MENTION=129311]Update[/MENTION];
2: MenuItems[i].OnClick := @About;
4: MenuItems[i].OnClick := @OpenThread;
5: MenuItems[i].OnClick := @Development;
end;
Simba_Menu.Add(MenuItems[i]);
end;
Strings := ['Officer Barbrady', 'Janilabo'];
h := High(Strings);
for i := 0 to h do
begin
HelpMenuItems[i] := TMenuItem.CREATE(MenuItems[3]);
HelpMenuItems[i].Caption := Strings[i];
HelpMenuItems[i].OnClick := @OpenMyProfile;
MenuItems[3].Add(HelpMenuItems[i]);
end;
end;
procedure Free;
begin
try
DsgnForm.free;
WriteLn('Simba Script Scanner Terminated!');
except
WriteLn('Error Freeing Form.');
end;
end;
begin
Init;
Free;
end.