Browse code

merge preliminary IS support

aCaB authored on 2009/07/15 06:44:03
Showing 28 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+ChangeLog merge=cl-merge
... ...
@@ -1,3 +1,31 @@
1
+Tue Jul 14 23:41:37 CEST 2009 (acab)
2
+------------------------------------
3
+ * libclamav: add preliminary support for IS executables (IS-cab and IS-msi)
4
+		part of bb#1571
5
+
6
+Tue Jul 14 18:17:59 CEST 2009 (tk)
7
+----------------------------------
8
+ * libclamav: add support for Universal Binaries (archives with Mach-O files for
9
+	      different architectures, bb#1592)
10
+
11
+Mon Jul 13 21:40:51 CEST 2009 (tk)
12
+----------------------------------
13
+ * docs/signatures.pdf: cover Mach-O files
14
+
15
+Mon Jul 13 21:24:05 CEST 2009 (tk)
16
+----------------------------------
17
+ * libclamav: handle Mach-O files with type-9 signatures; all special offsets are
18
+	      supported for PPC32/64 and x86 executables; for ARM and other archs
19
+	      only section based extensions (Sx[+-]n, SL[+-]n) are supported atm
20
+
21
+Mon Jul 13 19:34:36 EEST 2009 (edwin)
22
+-------------------------------------
23
+ * clambc/, libclamav/, unit_tests/: Initial draft of bytecode interpreter (bb #1243).
24
+
25
+Mon Jul 13 16:06:31 CEST 2009 (tk)
26
+----------------------------------
27
+ * libclamav/macho.c: handle LC_THREAD; calculate EP
28
+
1 29
 Fri Jul 10 10:10:35 CEST 2009 (tk)
2 30
 ----------------------------------
3 31
  * libclamav/filetypes_int.h: sync with daily.ftm
4 32
Binary files a/docs/signatures.pdf and b/docs/signatures.pdf differ
... ...
@@ -166,6 +166,8 @@ MalwareName:TargetType:Offset:HexSignature[:MinEngineFunctionalityLevel:[Max]]
166 166
 	\item 5 = Graphics
167 167
 	\item 6 = ELF
168 168
 	\item 7 = ASCII text file (normalized)
169
+	\item 8 = Disassembler data
170
+	\item 9 = Mach-O files
169 171
     \end{itemize}
170 172
     And	\verb+Offset+ is an asterisk or a decimal number \verb+n+ possibly
171 173
     combined with a special modifier:
... ...
@@ -174,7 +176,7 @@ MalwareName:TargetType:Offset:HexSignature[:MinEngineFunctionalityLevel:[Max]]
174 174
 	\item \verb+n+ = absolute offset
175 175
 	\item \verb+EOF-n+ = end of file minus \verb+n+ bytes
176 176
     \end{itemize}
177
-    Signatures for PE and ELF files additionally support:
177
+    Signatures for PE, ELF and Mach-O files additionally support:
178 178
     \begin{itemize}
179 179
 	\item \verb#EP+n# = entry point plus n bytes (\verb#EP+0# for \verb+EP+)
180 180
 	\item \verb#EP-n# = entry point minus n bytes
... ...
@@ -55,10 +55,10 @@ int cli_bytecode_context_clear(struct cli_bc_ctx *ctx)
55 55
     return CL_SUCCESS;
56 56
 }
57 57
 
58
-int cli_bytecode_context_setfuncid(struct cli_bc_ctx *ctx, struct cli_bc *bc, unsigned funcid)
58
+int cli_bytecode_context_setfuncid(struct cli_bc_ctx *ctx, const struct cli_bc *bc, unsigned funcid)
59 59
 {
60 60
     unsigned i;
61
-    struct cli_bc_func *func;
61
+    const struct cli_bc_func *func;
62 62
     if (funcid >= bc->num_func) {
63 63
 	cli_errmsg("bytecode: function ID doesn't exist: %u\n", funcid);
64 64
 	return CL_EARG;
... ...
@@ -275,7 +275,7 @@ static int parseHeader(struct cli_bc *bc, unsigned char *buffer)
275 275
     unsigned magic2;
276 276
     char ok = 1;
277 277
     unsigned offset, len, flevel;
278
-    if (strncmp(buffer, BC_HEADER, sizeof(BC_HEADER)-1)) {
278
+    if (strncmp((const char*)buffer, BC_HEADER, sizeof(BC_HEADER)-1)) {
279 279
 	cli_errmsg("Missing file magic in bytecode");
280 280
 	return CL_EMALFDB;
281 281
     }
... ...
@@ -481,10 +481,12 @@ static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, unsigned char
481 481
 	    case OP_SEXT:
482 482
 	    case OP_TRUNC:
483 483
 		inst.u.cast.source = readOperand(bcfunc, buffer, &offset, len, &ok);
484
-		if (ok) {
485
-		    /* calculate mask */
486
-		    inst.u.cast.mask = (1<<bcfunc->allinsts[inst.u.cast.source].type)-1;
487
-		}
484
+		inst.u.cast.mask = bcfunc->types[inst.u.cast.source];
485
+		/* calculate mask */
486
+		if (inst.opcode != OP_SEXT)
487
+		    inst.u.cast.mask = inst.u.cast.mask != 64 ?
488
+			(1ull<<inst.u.cast.mask)-1 :
489
+			~0ull;
488 490
 		break;
489 491
 	    default:
490 492
 		numOp = operand_counts[inst.opcode];
... ...
@@ -528,7 +530,7 @@ static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, unsigned char
528 528
 	    case OP_ICMP_SGE:
529 529
 	    case OP_ICMP_SLE:
530 530
 	    case OP_ICMP_SLT:
531
-		inst.type = bcfunc->allinsts[inst.u.binop[0]].type;
531
+		inst.type = bcfunc->types[inst.u.binop[0]];
532 532
 		break;
533 533
 	}
534 534
 	BB->insts[BB->numInsts++] = inst;
... ...
@@ -540,7 +542,6 @@ static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, unsigned char
540 540
 	}
541 541
 	offset++;
542 542
     }
543
-    cli_dbgmsg("Parsed %d instructions\n", BB->numInsts);
544 543
     if (offset != len) {
545 544
 	cli_errmsg("Trailing garbage in basicblock: %d extra bytes\n",
546 545
 		   len-offset);
... ...
@@ -598,6 +599,8 @@ int cli_bytecode_load(struct cli_bc *bc, FILE *f, struct cli_dbio *dbio)
598 598
 		    return rc;
599 599
 		}
600 600
 		if (bb >= bc->funcs[current_func].numBB) {
601
+		    cli_dbgmsg("Parsed %u BBs, %u instructions\n",
602
+			       bb, bc->funcs[current_func].numInsts);
601 603
 		    state = PARSE_FUNC_HEADER;
602 604
 		    current_func++;
603 605
 		}
... ...
@@ -613,7 +616,7 @@ int cli_bytecode_load(struct cli_bc *bc, FILE *f, struct cli_dbio *dbio)
613 613
     return CL_SUCCESS;
614 614
 }
615 615
 
616
-int cli_bytecode_run(struct cli_bc *bc, struct cli_bc_ctx *ctx)
616
+int cli_bytecode_run(const struct cli_bc *bc, struct cli_bc_ctx *ctx)
617 617
 {
618 618
     struct cli_bc_inst inst;
619 619
     struct cli_bc_func func;
... ...
@@ -40,7 +40,7 @@ struct cli_bc {
40 40
 };
41 41
 
42 42
 struct cli_bc_ctx *cli_bytecode_context_alloc(void);
43
-int cli_bytecode_context_setfuncid(struct cli_bc_ctx *ctx, struct cli_bc *bc, unsigned funcid);
43
+int cli_bytecode_context_setfuncid(struct cli_bc_ctx *ctx, const struct cli_bc *bc, unsigned funcid);
44 44
 int cli_bytecode_context_setparam_int(struct cli_bc_ctx *ctx, unsigned i, uint64_t c);
45 45
 int cli_bytecode_context_setparam_ptr(struct cli_bc_ctx *ctx, unsigned i, void *data, unsigned datalen);
46 46
 int cli_bytecode_context_clear(struct cli_bc_ctx *ctx);
... ...
@@ -48,7 +48,7 @@ uint64_t cli_bytecode_context_getresult_int(struct cli_bc_ctx *ctx);
48 48
 void cli_bytecode_context_destroy(struct cli_bc_ctx *ctx);
49 49
 
50 50
 int cli_bytecode_load(struct cli_bc *bc, FILE *f, struct cli_dbio *dbio);
51
-int cli_bytecode_run(struct cli_bc *bc, struct cli_bc_ctx *ctx);
51
+int cli_bytecode_run(const struct cli_bc *bc, struct cli_bc_ctx *ctx);
52 52
 void cli_bytecode_destroy(struct cli_bc *bc);
53 53
 
54 54
 #endif
... ...
@@ -86,8 +86,8 @@ struct cli_bc_func {
86 86
 
87 87
 struct cli_bc_ctx {
88 88
     /* id and params of toplevel function called */
89
-    struct cli_bc *bc;
90
-    struct cli_bc_func *func;
89
+    const struct cli_bc *bc;
90
+    const struct cli_bc_func *func;
91 91
     struct cli_bc_value *values;
92 92
     operand_t *operands;
93 93
     uint16_t funcid;
... ...
@@ -50,15 +50,6 @@ static int bcfail(const char *msg, long a, long b,
50 50
 #define CHECK_GT(a,b)
51 51
 #endif
52 52
 
53
-struct stack_entry {
54
-    const struct cli_bc_func *func;
55
-    struct cli_bc_value *ret;
56
-    struct cli_bc_value *values;
57
-    struct cli_bc_bb *bb;
58
-    unsigned bb_inst;
59
-};
60
-
61
-
62 53
 /* Get the operand of a binary operator, upper bits
63 54
  * (beyond the size of the operand) may have random values.
64 55
  * Use this when the active bits of the result of a binop are the same
... ...
@@ -70,17 +61,23 @@ struct stack_entry {
70 70
 #define UNOPNOMOD(i) (values[inst->u.binop[i]].v)
71 71
 
72 72
 /* get the operand of a binary operator, upper bits are cleared */
73
-#define BINOP(i) (BINOPNOMOD(i)&((1 << inst->type)-1))
74
-#define UNOP(x) (UNOPNOMOD(i)&((1 << inst->type)-1))
73
+#define type2mask(t) (inst->type == 64 ? ~0ull : (1ull << inst->type)-1)
74
+#define BINOP(i) (BINOPNOMOD(i)&type2mask(inst->type))
75
+#define UNOP(x) (UNOPNOMOD(i)&typemask(inst->type))
75 76
 
76 77
 /* get the operand as a signed value.
77 78
  * Warning: this assumes that result type is same as operand type.
78 79
  * This is usually true, except for icmp_* and select.
79 80
  * For icmp_* we fix it up in the loader. */
80
-#define SIGNEXT(a) CLI_SRS(((int64_t)(a)) << (64-inst->type), (64-inst->type))
81
-#define BINOPS(i) SIGNEXT(BINOPNOMOD(i))
81
+#define SIGNEXT(a, from) CLI_SRS(((int64_t)(a)) << (64-(from)), (64-(from)))
82
+#define BINOPS(i) SIGNEXT(BINOPNOMOD(i), inst->type)
83
+
84
+#define CASTOP (values[inst->u.cast.source].v& inst->u.cast.mask)
82 85
 
83
-static int jump(const struct cli_bc_func *func, uint16_t bbid, struct cli_bc_bb **bb, const struct cli_bc_inst **inst,
86
+#undef always_inline
87
+#define always_inline
88
+
89
+static always_inline int jump(const struct cli_bc_func *func, uint16_t bbid, struct cli_bc_bb **bb, const struct cli_bc_inst **inst,
84 90
 		unsigned *bb_inst)
85 91
 {
86 92
     CHECK_GT(func->numBB, bbid);
... ...
@@ -90,26 +87,164 @@ static int jump(const struct cli_bc_func *func, uint16_t bbid, struct cli_bc_bb
90 90
     return 0;
91 91
 }
92 92
 
93
-static struct cli_bc_value *allocate_stack(const struct cli_bc_func *func)
93
+#define STACK_CHUNKSIZE 16384
94
+
95
+struct stack_chunk {
96
+    struct stack_chunk *prev;
97
+    unsigned used;
98
+    union {
99
+	void *align;
100
+	char data[STACK_CHUNKSIZE];
101
+    } u;
102
+};
103
+
104
+struct stack {
105
+    struct stack_chunk* chunk;
106
+    uint16_t last_size;
107
+};
108
+
109
+static always_inline void* cli_stack_alloc(struct stack *stack, unsigned bytes)
110
+{
111
+    struct stack_chunk *chunk = stack->chunk;
112
+    uint16_t last_size_off;
113
+
114
+    /* last_size is stored after data */
115
+    /* align bytes to pointer size */
116
+    bytes = (bytes + sizeof(uint16_t) + sizeof(void*)) & ~(sizeof(void*)-1);
117
+    last_size_off = bytes - 2;
118
+
119
+    if (chunk && (chunk->used + bytes <= STACK_CHUNKSIZE)) {
120
+	/* there is still room in this chunk */
121
+	void *ret;
122
+
123
+	*(uint16_t*)&chunk->u.data[chunk->used + last_size_off] = stack->last_size;
124
+	stack->last_size = bytes/sizeof(void*);
125
+
126
+	ret = chunk->u.data + chunk->used;
127
+	chunk->used += bytes;
128
+	return ret;
129
+    }
130
+
131
+    if(bytes >= STACK_CHUNKSIZE) {
132
+	cli_errmsg("cli_stack_alloc: Attempt to allocate more than STACK_CHUNKSIZE bytes!\n");
133
+	return NULL;
134
+    }
135
+    /* not enough room here, allocate new chunk */
136
+    chunk = cli_malloc(sizeof(*stack->chunk));
137
+    if (!chunk)
138
+	return NULL;
139
+
140
+    *(uint16_t*)&chunk->u.data[last_size_off] = stack->last_size;
141
+    stack->last_size = bytes/sizeof(void*);
142
+
143
+    chunk->used = bytes;
144
+    chunk->prev = stack->chunk;
145
+    stack->chunk = chunk;
146
+    return chunk->u.data;
147
+}
148
+
149
+static always_inline void cli_stack_free(struct stack *stack, void *data)
150
+{
151
+    uint16_t last_size;
152
+    struct stack_chunk *chunk = stack->chunk;
153
+    if (!chunk) {
154
+	cli_errmsg("cli_stack_free: stack empty!\n");
155
+	return;
156
+    }
157
+    if ((chunk->u.data + chunk->used) != ((char*)data + stack->last_size*sizeof(void*))) {
158
+	cli_errmsg("cli_stack_free: wrong free order: %p, expected %p\n",
159
+		   data, chunk->u.data + chunk->used - stack->last_size*sizeof(void*));
160
+	return;
161
+    }
162
+    last_size = *(uint16_t*)&chunk->u.data[chunk->used-2];
163
+    if (chunk->used < stack->last_size*sizeof(void*)) {
164
+	cli_errmsg("cli_stack_free: last_size is corrupt!\n");
165
+	return;
166
+    }
167
+    chunk->used -= stack->last_size*sizeof(void*);
168
+    stack->last_size = last_size;
169
+    if (!chunk->used) {
170
+	stack->chunk = chunk->prev;
171
+	free(chunk);
172
+    }
173
+}
174
+
175
+static void cli_stack_destroy(struct stack *stack)
176
+{
177
+    struct stack_chunk *chunk = stack->chunk;
178
+    while (chunk) {
179
+	stack->chunk = chunk->prev;
180
+	free(chunk);
181
+	chunk = stack->chunk;
182
+    }
183
+}
184
+
185
+struct stack_entry {
186
+    struct stack_entry *prev;
187
+    const struct cli_bc_func *func;
188
+    struct cli_bc_value *ret;
189
+    struct cli_bc_bb *bb;
190
+    unsigned bb_inst;
191
+    struct cli_bc_value *values;
192
+};
193
+
194
+static always_inline struct stack_entry *allocate_stack(struct stack *stack,
195
+							struct stack_entry *prev,
196
+							const struct cli_bc_func *func,
197
+							const struct cli_bc_func *func_old,
198
+							struct cli_bc_value *ret,
199
+							struct cli_bc_bb *bb,
200
+							unsigned bb_inst)
94 201
 {
95 202
     unsigned i;
96
-    struct cli_bc_value *values = cli_malloc((func->numValues+func->numConstants)*sizeof(*values));
97
-    if (!values)
203
+    struct cli_bc_value *values;
204
+    const unsigned numValues = func->numValues + func->numConstants;
205
+    struct stack_entry *entry = cli_stack_alloc(stack, sizeof(*entry) + sizeof(*values)*numValues);
206
+    if (!entry)
98 207
 	return NULL;
99
-    for (i=func->numValues;i<func->numValues+func->numConstants;i++)
100
-	values[i] = func->constants[i-func->numValues];
101
-    return values;
208
+    entry->prev = prev;
209
+    entry->func = func_old;
210
+    entry->ret = ret;
211
+    entry->bb = bb;
212
+    entry->bb_inst = bb_inst;
213
+    /* we allocated room for values right after stack_entry! */
214
+    entry->values = values = (struct cli_bc_value*)&entry[1];
215
+
216
+    memcpy(&values[func->numValues], func->constants,
217
+	   sizeof(*values)*func->numConstants);
218
+    return entry;
219
+}
220
+
221
+static always_inline struct stack_entry *pop_stack(struct stack *stack,
222
+						   struct stack_entry *stack_entry,
223
+						   const struct cli_bc_func **func,
224
+						   struct cli_bc_value **ret,
225
+						   struct cli_bc_bb **bb,
226
+						   unsigned *bb_inst)
227
+{
228
+    void *data;
229
+    *func = stack_entry->func;
230
+    *ret = stack_entry->ret;
231
+    *bb = stack_entry->bb;
232
+    *bb_inst = stack_entry->bb_inst;
233
+    data = stack_entry;
234
+    stack_entry = stack_entry->prev;
235
+    cli_stack_free(stack, data);
236
+    return stack_entry;
102 237
 }
103 238
 
104 239
 int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct cli_bc_func *func, const struct cli_bc_inst *inst)
105 240
 {
106
-    unsigned i, stack_depth=0, bb_inst=0, stop=0, stack_max_depth=0;
241
+    uint64_t tmp;
242
+    unsigned i, stack_depth=0, bb_inst=0, stop=0 ;
107 243
     struct cli_bc_func *func2;
108
-    struct stack_entry *stack = NULL;
244
+    struct stack stack;
245
+    struct stack_entry *stack_entry = NULL;
109 246
     struct cli_bc_bb *bb = NULL;
110 247
     struct cli_bc_value *values = ctx->values;
111 248
     struct cli_bc_value *value, *old_values;
112 249
 
250
+    memset(&stack, 0, sizeof(stack));
113 251
     do {
114 252
 	value = &values[inst->dest];
115 253
 	CHECK_GT(func->numValues+func->numConstants, value - values);
... ...
@@ -126,8 +261,10 @@ int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct
126 126
 	    case OP_UDIV:
127 127
 		{
128 128
 		    uint64_t d = BINOP(1);
129
-		    if (UNLIKELY(!d))
129
+		    if (UNLIKELY(!d)) {
130
+			cli_dbgmsg("bytecode attempted to execute udiv#0\n");
130 131
 			return CL_EBYTECODE;
132
+		    }
131 133
 		    value->v = BINOP(0) / d;
132 134
 		    break;
133 135
 		}
... ...
@@ -135,16 +272,20 @@ int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct
135 135
 		{
136 136
 		    int64_t a = BINOPS(0);
137 137
 		    int64_t b = BINOPS(1);
138
-		    if (UNLIKELY(b == 0 || (b == -1 && a == (-9223372036854775807LL-1LL))))
138
+		    if (UNLIKELY(b == 0 || (b == -1 && a == (-9223372036854775807LL-1LL)))) {
139
+			cli_dbgmsg("bytecode attempted to execute sdiv#0\n");
139 140
 			return CL_EBYTECODE;
141
+		    }
140 142
 		    value->v = a / b;
141 143
 		    break;
142 144
 		}
143 145
 	    case OP_UREM:
144 146
 		{
145 147
 		    uint64_t d = BINOP(1);
146
-		    if (UNLIKELY(!d))
148
+		    if (UNLIKELY(!d)) {
149
+			cli_dbgmsg("bytecode attempted to execute urem#0\n");
147 150
 			return CL_EBYTECODE;
151
+		    }
148 152
 		    value->v = BINOP(0) % d;
149 153
 		    break;
150 154
 		}
... ...
@@ -152,8 +293,10 @@ int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct
152 152
 		{
153 153
 		    int64_t a = BINOPS(0);
154 154
 		    int64_t b = BINOPS(1);
155
-		    if (UNLIKELY(b == 0 || (b == -1 && (a == -9223372036854775807LL-1LL))))
155
+		    if (UNLIKELY(b == 0 || (b == -1 && (a == -9223372036854775807LL-1LL)))) {
156
+			cli_dbgmsg("bytecode attempted to execute srem#0\n");
156 157
 			return CL_EBYTECODE;
158
+		    }
157 159
 		    value->v = a % b;
158 160
 		    break;
159 161
 		}
... ...
@@ -179,12 +322,13 @@ int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct
179 179
 		value->v = BINOPNOMOD(0) ^ BINOPNOMOD(1);
180 180
 		break;
181 181
 	    case OP_SEXT:
182
-		value->v = SIGNEXT(values[inst->u.cast.source].v);
182
+		/* mask is number of src bits here, not a mask! */
183
+		value->v = SIGNEXT(values[inst->u.cast.source].v, inst->u.cast.mask);
183 184
 		break;
184 185
 	    case OP_TRUNC:
185 186
 		/* fall-through */
186 187
 	    case OP_ZEXT:
187
-		value->v = values[inst->u.cast.source].v & values[inst->u.cast.mask].v;
188
+		value->v = CASTOP;
188 189
 		break;
189 190
 	    case OP_BRANCH:
190 191
 		stop = jump(func, (values[inst->u.branch.condition].v&1) ?
... ...
@@ -196,31 +340,13 @@ int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct
196 196
 		continue;
197 197
 	    case OP_RET:
198 198
 		CHECK_GT(stack_depth, 0);
199
-		stack_depth--;
200
-		value = stack[stack_depth].ret;
201
-		func = stack[stack_depth].func;
202
-		value->v = values[inst->u.unaryop].v;
203
-		old_values = values;
204
-		values = stack[stack_depth].values;
205
-		stack[stack_depth].values = old_values;
199
+		tmp = values[inst->u.unaryop].v;
200
+		stack_entry = pop_stack(&stack, stack_entry, &func, &value, &bb,
201
+					&bb_inst);
202
+		values = stack_entry ? stack_entry->values : ctx->values;
206 203
 		CHECK_GT(func->numValues+func->numConstants, value-values);
207 204
 		CHECK_GT(value-values, -1);
208
-		bb = stack[stack_depth].bb;
209
-		bb_inst = stack[stack_depth].bb_inst;
210
-		if ((stack_depth < stack_max_depth*3/4) || !stack_depth) {
211
-		    for (i=stack_depth;i<stack_max_depth;i++) {
212
-			free(stack[i].values);
213
-		    }
214
-		    if (!stack_depth) {
215
-			free(stack);
216
-			stack = 0;
217
-		    } else {
218
-			stack = cli_realloc2(stack, sizeof(*stack)*stack_depth);
219
-			if (!stack)
220
-			    return CL_EMEM;
221
-		    }
222
-		    stack_max_depth = stack_depth;
223
-		}
205
+		value->v = tmp;
224 206
 		if (!bb) {
225 207
 		    stop = CL_BREAK;
226 208
 		    continue;
... ...
@@ -266,29 +392,16 @@ int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct
266 266
 		func2 = &bc->funcs[inst->u.ops.funcid];
267 267
 		CHECK_EQ(func2->numArgs, inst->u.ops.numOps);
268 268
 		old_values = values;
269
-		if (stack_depth+1 > stack_max_depth) {
270
-		    stack = cli_realloc2(stack, sizeof(*stack)*(stack_depth+1));
271
-		    if (!stack)
272
-			return CL_EMEM;
273
-		    stack_max_depth = stack_depth+1;
274
-		    values = allocate_stack(func2);
275
-		    if (!values)
276
-			return CL_EMEM;
277
-		} else {
278
-		    values = stack[stack_depth].values;
279
-		}
280
-		stack[stack_depth].func = func;
281
-		stack[stack_depth].ret = value;
282
-		stack[stack_depth].bb = bb;
283
-		stack[stack_depth].bb_inst = bb_inst;
284
-		stack[stack_depth].values = old_values;
285
-		stack_depth++;
286
-//cli_dbgmsg("Executing %d\n", inst->u.ops.funcid);
269
+		stack_entry = allocate_stack(&stack, stack_entry, func2, func, value,
270
+					     bb, bb_inst);
271
+		values = stack_entry->values;
272
+//		cli_dbgmsg("Executing %d\n", inst->u.ops.funcid);
287 273
 		for (i=0;i<func2->numArgs;i++)
288 274
 		    values[i] = old_values[inst->u.ops.ops[i]];
289 275
 		func = func2;
290 276
 		CHECK_GT(func->numBB, 0);
291 277
 		stop = jump(func, 0, &bb, &inst, &bb_inst);
278
+		stack_depth++;
292 279
 		continue;
293 280
 	    case OP_COPY:
294 281
 		BINOPNOMOD(1) = BINOPNOMOD(0);
... ...
@@ -303,6 +416,6 @@ int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct
303 303
 	CHECK_GT(bb->numInsts, bb_inst);
304 304
     } while (stop == CL_SUCCESS);
305 305
 
306
-    free(stack);
306
+    cli_stack_destroy(&stack);
307 307
     return stop == CL_BREAK ? CL_SUCCESS : stop;
308 308
 }
... ...
@@ -80,70 +80,7 @@ struct cpio_hdr_newc {
80 80
     char check[8];
81 81
 };
82 82
 
83
-#ifndef O_BINARY
84
-#define O_BINARY    0
85
-#endif
86
-
87
-static int cpio_scanfile(int fd, uint32_t size, cli_ctx *ctx)
88
-{
89
-	int newfd, bread, sum = 0, ret;
90
-	char buff[FILEBUFF];
91
-	char *name;
92
-
93
-
94
-    if(!(name = cli_gentemp(ctx->engine->tmpdir)))
95
-	return CL_EMEM;
96
-
97
-    if((newfd = open(name, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
98
-	cli_errmsg("cpio_scanfile: Can't create file %s\n", name);
99
-	free(name);
100
-	return CL_ECREAT;
101
-    }
102
-
103
-    while((bread = cli_readn(fd, buff, FILEBUFF)) > 0) {
104
-	if((uint32_t) (sum + bread) >= size) {
105
-	    if(write(newfd, buff, size - sum) == -1) {
106
-		cli_errmsg("cpio_scanfile: Can't write to %s\n", name);
107
-		cli_unlink(name);
108
-		free(name);
109
-		close(newfd);
110
-		return CL_EWRITE;
111
-	    }
112
-	    break;
113
-	} else {
114
-	    if(write(newfd, buff, bread) == -1) {
115
-		cli_errmsg("cpio_scanfile: Can't write to %s\n", name);
116
-		cli_unlink(name);
117
-		free(name);
118
-		close(newfd);
119
-		return CL_EWRITE;
120
-	    }
121
-	}
122
-	sum += bread;
123
-    }
124
-    cli_dbgmsg("CPIO: Extracted to %s\n", name);
125
-    lseek(newfd, 0, SEEK_SET);
126
-    if((ret = cli_magic_scandesc(newfd, ctx)) == CL_VIRUS)
127
-	cli_dbgmsg("cpio_scanfile: Infected with %s\n", *ctx->virname);
128
-
129
-    close(newfd);
130
-    if(!ctx->engine->keeptmp) {
131
-	if(cli_unlink(name)) {
132
-	    free(name);
133
-	    return CL_EUNLINK;
134
-	}
135
-    }
136
-    free(name);
137
-    return ret;
138
-}
139
-
140
-static inline uint16_t EC16(uint16_t v, int c)
141
-{
142
-    if(!c)
143
-	return v;
144
-    else
145
-	return ((v >> 8) + (v << 8));
146
-}
83
+#define EC16(v, conv)   (conv ? cbswap16(v) : v)
147 84
 
148 85
 static void sanitname(char *name)
149 86
 {
... ...
@@ -213,7 +150,7 @@ int cli_scancpio_old(int fd, cli_ctx *ctx)
213 213
 	    if(ret == CL_EMAXFILES) {
214 214
 		return ret;
215 215
 	    } else if(ret == CL_SUCCESS) {
216
-		ret = cpio_scanfile(fd, filesize, ctx);
216
+		ret = cli_dumpscan(fd, 0, filesize, ctx);
217 217
 		if(ret == CL_VIRUS)
218 218
 		    return ret;
219 219
 	    }
... ...
@@ -287,7 +224,7 @@ int cli_scancpio_odc(int fd, cli_ctx *ctx)
287 287
 	if(ret == CL_EMAXFILES) {
288 288
 	    return ret;
289 289
 	} else if(ret == CL_SUCCESS) {
290
-	    ret = cpio_scanfile(fd, filesize, ctx);
290
+	    ret = cli_dumpscan(fd, 0, filesize, ctx);
291 291
 	    if(ret == CL_VIRUS)
292 292
 		return ret;
293 293
 	}
... ...
@@ -363,7 +300,7 @@ int cli_scancpio_newc(int fd, cli_ctx *ctx, int crc)
363 363
 	if(ret == CL_EMAXFILES) {
364 364
 	    return ret;
365 365
 	} else if(ret == CL_SUCCESS) {
366
-	    ret = cpio_scanfile(fd, filesize, ctx);
366
+	    ret = cli_dumpscan(fd, 0, filesize, ctx);
367 367
 	    if(ret == CL_VIRUS)
368 368
 		return ret;
369 369
 	}
... ...
@@ -39,21 +39,8 @@
39 39
 #include "execs.h"
40 40
 #include "matcher.h"
41 41
 
42
-static inline uint16_t EC16(uint16_t v, uint8_t c)
43
-{
44
-    if(!c)
45
-	return v;
46
-    else
47
-	return ((v >> 8) + (v << 8));
48
-}
49
-
50
-static inline uint32_t EC32(uint32_t v, uint8_t c)
51
-{
52
-    if(!c)
53
-	return v;
54
-    else
55
-	return ((v >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | (v << 24));
56
-}
42
+#define EC16(v, conv)   (conv ? cbswap16(v) : v)
43
+#define EC32(v, conv)   (conv ? cbswap32(v) : v)
57 44
 
58 45
 static uint32_t cli_rawaddr(uint32_t vaddr, struct elf_program_hdr32 *ph, uint16_t phnum, uint8_t conv, uint8_t *err)
59 46
 {
... ...
@@ -57,6 +57,7 @@ static const struct ftmap_s {
57 57
     { "CL_TYPE_MSEXE",		CL_TYPE_MSEXE		},
58 58
     { "CL_TYPE_ELF",		CL_TYPE_ELF		},
59 59
     { "CL_TYPE_MACHO",		CL_TYPE_MACHO		},
60
+    { "CL_TYPE_MACHO_UNIBIN",	CL_TYPE_MACHO_UNIBIN	},
60 61
     { "CL_TYPE_POSIX_TAR",	CL_TYPE_POSIX_TAR	},
61 62
     { "CL_TYPE_OLD_TAR",	CL_TYPE_OLD_TAR		},
62 63
     { "CL_TYPE_CPIO_OLD",	CL_TYPE_CPIO_OLD	},
... ...
@@ -42,6 +42,7 @@ typedef enum {
42 42
     CL_TYPE_PE_DISASM,
43 43
     CL_TYPE_ELF,
44 44
     CL_TYPE_MACHO,
45
+    CL_TYPE_MACHO_UNIBIN,
45 46
     CL_TYPE_POSIX_TAR,
46 47
     CL_TYPE_OLD_TAR,
47 48
     CL_TYPE_CPIO_OLD,
... ...
@@ -149,6 +149,7 @@ static const char *ftypes_int[] = {
149 149
   "0:0:feedface:Mach-O BE:CL_TYPE_ANY:CL_TYPE_MACHO:45",
150 150
   "0:0:feedfacf:Mach-O BE 64-bit:CL_TYPE_ANY:CL_TYPE_MACHO:45",
151 151
   "1:*:496e7374616c6c536869656c6400{292}0600000000000000{8}0000000001:ISHIELD-MSI:CL_TYPE_ANY:CL_TYPE_ISHIELD_MSI:45",
152
+  "0:0:cafebabe:Universal Binary:CL_TYPE_ANY:CL_TYPE_MACHO_UNIBIN:46",
152 153
   NULL
153 154
 };
154 155
 
... ...
@@ -18,14 +18,10 @@
18 18
  *  MA 02110-1301, USA.
19 19
  */
20 20
 
21
-/* TODO:
22
- *  - handle LC_THREAD
23
- *  - integrate with the matcher
24
- */
25
-
26 21
 #include <stdio.h>
27 22
 #include <string.h>
28 23
 #include <unistd.h>
24
+#include <stdlib.h>
29 25
 #include <sys/types.h>
30 26
 #include <sys/stat.h>
31 27
 #include <fcntl.h>
... ...
@@ -112,7 +108,98 @@ struct macho_section64
112 112
     uint32_t res2;
113 113
 };
114 114
 
115
-int cli_scanmacho(int fd, cli_ctx *ctx)
115
+struct macho_thread_state_ppc
116
+{
117
+    uint32_t srr0; /* PC */
118
+    uint32_t srr1;
119
+    uint32_t reg[32];
120
+    uint32_t cr;
121
+    uint32_t xer;
122
+    uint32_t lr;
123
+    uint32_t ctr;
124
+    uint32_t mq;
125
+    uint32_t vrsave;
126
+};
127
+
128
+struct macho_thread_state_ppc64
129
+{
130
+    uint64_t srr0; /* PC */
131
+    uint64_t srr1;
132
+    uint64_t reg[32];
133
+    uint32_t cr;
134
+    uint64_t xer;
135
+    uint64_t lr;
136
+    uint64_t ctr;
137
+    uint32_t vrsave;
138
+};
139
+
140
+struct macho_thread_state_x86
141
+{
142
+    uint32_t eax;
143
+    uint32_t ebx;
144
+    uint32_t ecx;
145
+    uint32_t edx;
146
+    uint32_t edi;
147
+    uint32_t esi;
148
+    uint32_t ebp;
149
+    uint32_t esp;
150
+    uint32_t ss;
151
+    uint32_t eflags;
152
+    uint32_t eip;
153
+    uint32_t cs;
154
+    uint32_t ds;
155
+    uint32_t es;
156
+    uint32_t fs;
157
+    uint32_t gs;
158
+};
159
+
160
+struct macho_fat_header
161
+{
162
+    uint32_t magic;
163
+    uint32_t nfats;
164
+};
165
+
166
+struct macho_fat_arch
167
+{
168
+    uint32_t cputype;
169
+    uint32_t cpusubtype;
170
+    uint32_t offset;
171
+    uint32_t size;
172
+    uint32_t align;
173
+};
174
+
175
+#define RETURN_BROKEN					    \
176
+    if(matcher)						    \
177
+	return -1;					    \
178
+    if(DETECT_BROKEN) {					    \
179
+	if(ctx->virname)				    \
180
+	    *ctx->virname = "Broken.Executable";	    \
181
+	return cli_checkfp(fd, ctx) ? CL_CLEAN : CL_VIRUS;  \
182
+    }							    \
183
+    return CL_EFORMAT
184
+
185
+
186
+static uint32_t cli_rawaddr(uint32_t vaddr, struct cli_exe_section *sects, uint16_t nsects, unsigned int *err)
187
+{
188
+	unsigned int i, found = 0;
189
+
190
+    for(i = 0; i < nsects; i++) {
191
+	if(sects[i].rva <= vaddr && sects[i].rva + sects[i].vsz > vaddr) {
192
+	    found = 1;
193
+	    break;
194
+	}
195
+    }
196
+
197
+    if(!found) {
198
+	*err = 1;
199
+	return 0;
200
+    }
201
+
202
+    *err = 0;
203
+    return vaddr - sects[i].rva + sects[i].raw;
204
+}
205
+
206
+int cli_scanmacho(int fd, cli_ctx *ctx, struct cli_exe_info *fileinfo)
116 207
 {
117 208
 	struct macho_hdr hdr;
118 209
 	struct macho_load_cmd load_cmd;
... ...
@@ -120,12 +207,17 @@ int cli_scanmacho(int fd, cli_ctx *ctx)
120 120
 	struct macho_segment_cmd64 segment_cmd64;
121 121
 	struct macho_section section;
122 122
 	struct macho_section64 section64;
123
-	unsigned int i, j, sect = 0, conv, m64, nsects, vaddr, vsize, offset;
123
+	unsigned int i, j, sect = 0, conv, m64, nsects, matcher = 0;
124
+	unsigned int arch = 0, ep = 0, err;
125
+	struct cli_exe_section *sections = NULL;
124 126
 	char name[16];
125 127
 
128
+    if(fileinfo)
129
+	matcher = 1;
130
+
126 131
     if(read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
127 132
 	cli_dbgmsg("cli_scanmacho: Can't read header\n");
128
-	return CL_EFORMAT;
133
+	return matcher ? -1 : CL_EFORMAT;
129 134
     }
130 135
 
131 136
     if(hdr.magic == 0xfeedface) {
... ...
@@ -142,34 +234,44 @@ int cli_scanmacho(int fd, cli_ctx *ctx)
142 142
 	m64 = 1;
143 143
     } else {
144 144
 	cli_dbgmsg("cli_scanmacho: Incorrect magic\n");
145
-	return CL_EFORMAT;
145
+	return matcher ? -1 : CL_EFORMAT;
146 146
     }
147 147
 
148 148
     switch(EC32(hdr.cpu_type, conv)) {
149 149
 	case 7:
150
-	    cli_dbgmsg("MACHO: CPU Type: Intel 32-bit\n");
150
+	    if(!matcher)
151
+		cli_dbgmsg("MACHO: CPU Type: Intel 32-bit\n");
152
+	    arch = 1;
151 153
 	    break;
152 154
 	case 7 | 0x1000000:
153
-	    cli_dbgmsg("MACHO: CPU Type: Intel 64-bit\n");
155
+	    if(!matcher)
156
+		cli_dbgmsg("MACHO: CPU Type: Intel 64-bit\n");
154 157
 	    break;
155 158
 	case 12:
156
-	    cli_dbgmsg("MACHO: CPU Type: ARM\n");
159
+	    if(!matcher)
160
+		cli_dbgmsg("MACHO: CPU Type: ARM\n");
157 161
 	    break;
158 162
 	case 14:
159
-	    cli_dbgmsg("MACHO: CPU Type: SPARC\n");
163
+	    if(!matcher)
164
+		cli_dbgmsg("MACHO: CPU Type: SPARC\n");
160 165
 	    break;
161 166
 	case 18:
162
-	    cli_dbgmsg("MACHO: CPU Type: POWERPC 32-bit\n");
167
+	    if(!matcher)
168
+		cli_dbgmsg("MACHO: CPU Type: POWERPC 32-bit\n");
169
+	    arch = 2;
163 170
 	    break;
164 171
 	case 18 | 0x1000000:
165
-	    cli_dbgmsg("MACHO: CPU Type: POWERPC 64-bit\n");
172
+	    if(!matcher)
173
+		cli_dbgmsg("MACHO: CPU Type: POWERPC 64-bit\n");
174
+	    arch = 3;
166 175
 	    break;
167 176
 	default:
168
-	    cli_dbgmsg("MACHO: CPU Type: ** UNKNOWN ** (%u)\n", EC32(hdr.cpu_type, conv));
177
+	    if(!matcher)
178
+		cli_dbgmsg("MACHO: CPU Type: ** UNKNOWN ** (%u)\n", EC32(hdr.cpu_type, conv));
169 179
 	    break;
170 180
     }
171 181
 
172
-    switch(EC32(hdr.filetype, conv)) {
182
+    if(!matcher) switch(EC32(hdr.filetype, conv)) {
173 183
 	case 0x1: /* MH_OBJECT */
174 184
 	    cli_dbgmsg("MACHO: Filetype: Relocatable object file\n");
175 185
 	    break;
... ...
@@ -201,198 +303,246 @@ int cli_scanmacho(int fd, cli_ctx *ctx)
201 201
 	    cli_dbgmsg("MACHO: Filetype: ** UNKNOWN ** (0x%x)\n", EC32(hdr.filetype, conv));
202 202
     }
203 203
 
204
-    cli_dbgmsg("MACHO: Number of load commands: %u\n", EC32(hdr.ncmds, conv));
205
-    cli_dbgmsg("MACHO: Size of load commands: %u\n", EC32(hdr.sizeofcmds, conv));
206
-
207
-    if((m64 && EC32(load_cmd.cmdsize, conv) % 8) || (!m64 && EC32(load_cmd.cmdsize, conv) % 4)) {
208
-	cli_dbgmsg("cli_scanmacho: Invalid command size (%u)\n", EC32(load_cmd.cmdsize, conv));
209
-        if(DETECT_BROKEN) {
210
-	    if(ctx->virname)
211
-		*ctx->virname = "Broken.Executable";
212
-	    return cli_checkfp(fd, ctx) ? CL_CLEAN : CL_VIRUS;
213
-        }
214
-	return CL_EFORMAT;
204
+    if(!matcher) {
205
+	cli_dbgmsg("MACHO: Number of load commands: %u\n", EC32(hdr.ncmds, conv));
206
+	cli_dbgmsg("MACHO: Size of load commands: %u\n", EC32(hdr.sizeofcmds, conv));
215 207
     }
216 208
 
217 209
     if(m64)
218 210
 	lseek(fd, 4, SEEK_CUR);
219 211
 
220
-    for(i = 0; i < EC32(hdr.ncmds, conv); i++) {
212
+    hdr.ncmds = EC32(hdr.ncmds, conv);
213
+    if(!hdr.ncmds || hdr.ncmds > 1024) {
214
+	cli_dbgmsg("cli_scanmacho: Invalid number of load commands (%u)\n", hdr.ncmds);
215
+	RETURN_BROKEN;
216
+    }
217
+
218
+    for(i = 0; i < hdr.ncmds; i++) {
221 219
 	if(read(fd, &load_cmd, sizeof(load_cmd)) != sizeof(load_cmd)) {
222 220
 	    cli_dbgmsg("cli_scanmacho: Can't read load command\n");
223
-	    if(DETECT_BROKEN) {
224
-		if(ctx->virname)
225
-		    *ctx->virname = "Broken.Executable";
226
-		return cli_checkfp(fd, ctx) ? CL_CLEAN : CL_VIRUS;
227
-	    }
228
-	    return CL_EFORMAT;
221
+	    free(sections);
222
+	    RETURN_BROKEN;
229 223
 	}
230
-
231
-	if((m64 && EC32(load_cmd.cmd, conv) == 0x19) || (!m64 && EC32(load_cmd.cmd, conv) == 0x01)) { /* LC_SEGMENT */
224
+	/*
225
+	if((m64 && EC32(load_cmd.cmdsize, conv) % 8) || (!m64 && EC32(load_cmd.cmdsize, conv) % 4)) {
226
+	    cli_dbgmsg("cli_scanmacho: Invalid command size (%u)\n", EC32(load_cmd.cmdsize, conv));
227
+	    free(sections);
228
+	    RETURN_BROKEN;
229
+	}
230
+	*/
231
+	load_cmd.cmd = EC32(load_cmd.cmd, conv);
232
+	if((m64 && load_cmd.cmd == 0x19) || (!m64 && load_cmd.cmd == 0x01)) { /* LC_SEGMENT */
232 233
 	    if(m64) {
233 234
 		if(read(fd, &segment_cmd64, sizeof(segment_cmd64)) != sizeof(segment_cmd64)) {
234 235
 		    cli_dbgmsg("cli_scanmacho: Can't read segment command\n");
235
-		    if(DETECT_BROKEN) {
236
-			if(ctx->virname)
237
-			    *ctx->virname = "Broken.Executable";
238
-			return cli_checkfp(fd, ctx) ? CL_CLEAN : CL_VIRUS;
239
-		    }
240
-		    return CL_EFORMAT;
236
+		    free(sections);
237
+		    RETURN_BROKEN;
241 238
 		}
242 239
 		nsects = EC32(segment_cmd64.nsects, conv);
243 240
 		strncpy(name, segment_cmd64.segname, 16);
244 241
 	    } else {
245 242
 		if(read(fd, &segment_cmd, sizeof(segment_cmd)) != sizeof(segment_cmd)) {
246 243
 		    cli_dbgmsg("cli_scanmacho: Can't read segment command\n");
247
-		    if(DETECT_BROKEN) {
248
-			if(ctx->virname)
249
-			    *ctx->virname = "Broken.Executable";
250
-			return cli_checkfp(fd, ctx) ? CL_CLEAN : CL_VIRUS;
251
-		    }
252
-		    return CL_EFORMAT;
244
+		    free(sections);
245
+		    RETURN_BROKEN;
253 246
 		}
254 247
 		nsects = EC32(segment_cmd.nsects, conv);
255 248
 		strncpy(name, segment_cmd.segname, 16);
256 249
 	    }
257
-	    name[15] = 0;
258
-	    cli_dbgmsg("MACHO: Segment name: %s\n", name);
259
-	    cli_dbgmsg("MACHO: Number of sections: %u\n", nsects);
250
+	    if(!matcher) {
251
+		name[15] = 0;
252
+		cli_dbgmsg("MACHO: Segment name: %s\n", name);
253
+		cli_dbgmsg("MACHO: Number of sections: %u\n", nsects);
254
+	    }
255
+	    if(nsects > 255) {
256
+		cli_dbgmsg("cli_scanmacho: Invalid number of sections\n");
257
+		free(sections);
258
+		RETURN_BROKEN;
259
+	    }
260
+	    if(!nsects) {
261
+		if(!matcher)
262
+		    cli_dbgmsg("MACHO: ------------------\n");
263
+		continue;
264
+	    }
265
+	    sections = (struct cli_exe_section *) cli_realloc2(sections, (sect + nsects) * sizeof(struct cli_exe_section));
266
+	    if(!sections) {
267
+		cli_errmsg("cli_scanmacho: Can't allocate memory for 'sections'\n");
268
+		return matcher ? -1 : CL_EMEM;
269
+	    }
270
+
260 271
 	    for(j = 0; j < nsects; j++) {
261 272
 		if(m64) {
262 273
 		    if(read(fd, &section64, sizeof(section64)) != sizeof(section64)) {
263 274
 			cli_dbgmsg("cli_scanmacho: Can't read section\n");
264
-			if(DETECT_BROKEN) {
265
-			    if(ctx->virname)
266
-				*ctx->virname = "Broken.Executable";
267
-			    return cli_checkfp(fd, ctx) ? CL_CLEAN : CL_VIRUS;
268
-			}
269
-			return CL_EFORMAT;
275
+			free(sections);
276
+			RETURN_BROKEN;
270 277
 		    }
271
-		    vaddr = EC64(section64.addr, conv);
272
-		    vsize = EC64(section64.size, conv);
273
-		    offset = EC32(section64.offset, conv);
278
+		    sections[sect].rva = EC64(section64.addr, conv);
279
+		    sections[sect].vsz = EC64(section64.size, conv);
280
+		    sections[sect].raw = EC32(section64.offset, conv);
281
+		    section64.align = EC32(section64.align, conv);
282
+		    sections[sect].rsz = sections[sect].vsz + (section64.align - (sections[sect].vsz % section64.align)) % section64.align; /* most likely we can assume it's the same as .vsz */
274 283
 		    strncpy(name, section64.sectname, 16);
275 284
 		} else {
276 285
 		    if(read(fd, &section, sizeof(section)) != sizeof(section)) {
277 286
 			cli_dbgmsg("cli_scanmacho: Can't read section\n");
278
-			if(DETECT_BROKEN) {
279
-			    if(ctx->virname)
280
-				*ctx->virname = "Broken.Executable";
281
-			    return cli_checkfp(fd, ctx) ? CL_CLEAN : CL_VIRUS;
282
-			}
283
-			return CL_EFORMAT;
287
+			free(sections);
288
+			RETURN_BROKEN;
284 289
 		    }
285
-		    vaddr = EC32(section.addr, conv);
286
-		    vsize = EC32(section.size, conv);
287
-		    offset = EC32(section.offset, conv);
290
+		    sections[sect].rva = EC32(section.addr, conv);
291
+		    sections[sect].vsz = EC32(section.size, conv);
292
+		    sections[sect].raw = EC32(section.offset, conv);
293
+		    section.align = EC32(section.align, conv);
294
+		    sections[sect].rsz = sections[sect].vsz + (section.align - (sections[sect].vsz % section.align)) % section.align;
288 295
 		    strncpy(name, section.sectname, 16);
289 296
 		}
290
-		name[15] = 0;
291
-		cli_dbgmsg("MACHO: --- Section %u ---\n", sect);
292
-		cli_dbgmsg("MACHO: Name: %s\n", name);
293
-		cli_dbgmsg("MACHO: Virtual address: 0x%x\n", vaddr);
294
-		cli_dbgmsg("MACHO: Virtual size: %u\n", vsize);
295
-		if(offset)
296
-		    cli_dbgmsg("MACHO: File offset: %u\n", offset);
297
+		if(!matcher) {
298
+		    name[15] = 0;
299
+		    cli_dbgmsg("MACHO: --- Section %u ---\n", sect);
300
+		    cli_dbgmsg("MACHO: Name: %s\n", name);
301
+		    cli_dbgmsg("MACHO: Virtual address: 0x%x\n", (unsigned int) sections[sect].rva);
302
+		    cli_dbgmsg("MACHO: Virtual size: %u\n", (unsigned int) sections[sect].vsz);
303
+		    cli_dbgmsg("MACHO: Raw size: %u\n", (unsigned int) sections[sect].rsz);
304
+		    if(sections[sect].raw)
305
+			cli_dbgmsg("MACHO: File offset: %u\n", (unsigned int) sections[sect].raw);
306
+		}
297 307
 		sect++;
298 308
 	    }
299
-	    cli_dbgmsg("MACHO: ------------------\n");
309
+	    if(!matcher)
310
+		cli_dbgmsg("MACHO: ------------------\n");
311
+
312
+	} else if(arch && (load_cmd.cmd == 0x4 || load_cmd.cmd == 0x5)) { /* LC_(UNIX)THREAD */
313
+	    lseek(fd, 8, SEEK_CUR);
314
+	    switch(arch) {
315
+		case 1: /* x86 */
316
+		{
317
+			struct macho_thread_state_x86 thread_state_x86;
318
+
319
+		    if(read(fd, &thread_state_x86, sizeof(thread_state_x86)) != sizeof(thread_state_x86)) {
320
+			cli_dbgmsg("cli_scanmacho: Can't read thread_state_x86\n");
321
+			free(sections);
322
+			RETURN_BROKEN;
323
+		    }
324
+		    break;
325
+		}
326
+
327
+		case 2: /* PPC */
328
+		{
329
+			struct macho_thread_state_ppc thread_state_ppc;
330
+
331
+		    if(read(fd, &thread_state_ppc, sizeof(thread_state_ppc)) != sizeof(thread_state_ppc)) {
332
+			cli_dbgmsg("cli_scanmacho: Can't read thread_state_ppc\n");
333
+			free(sections);
334
+			RETURN_BROKEN;
335
+		    }
336
+		    ep = EC32(thread_state_ppc.srr0, conv);
337
+		    break;
338
+		}
339
+
340
+		case 3: /* PPC64 */
341
+		{
342
+			struct macho_thread_state_ppc64 thread_state_ppc64;
343
+
344
+		    if(read(fd, &thread_state_ppc64, sizeof(thread_state_ppc64)) != sizeof(thread_state_ppc64)) {
345
+			cli_dbgmsg("cli_scanmacho: Can't read thread_state_ppc64\n");
346
+			free(sections);
347
+			RETURN_BROKEN;
348
+		    }
349
+		    ep = EC64(thread_state_ppc64.srr0, conv);
350
+		    break;
351
+		}
352
+		default:
353
+		    cli_errmsg("cli_scanmacho: Invalid arch setting!\n");
354
+		    free(sections);
355
+		    return matcher ? -1 : CL_EARG;
356
+	    }
300 357
 	} else {
301 358
 	    if(EC32(load_cmd.cmdsize, conv) > sizeof(load_cmd))
302 359
 		lseek(fd, EC32(load_cmd.cmdsize, conv) - sizeof(load_cmd), SEEK_CUR);
303 360
 	}
304 361
     }
305 362
 
306
-    return CL_SUCCESS;
363
+    if(ep) {
364
+	if(!matcher)
365
+	    cli_dbgmsg("Entry Point: 0x%x\n", ep);
366
+	if(sections) {
367
+	    ep = cli_rawaddr(ep, sections, sect, &err);
368
+	    if(err) {
369
+		cli_dbgmsg("cli_scanmacho: Can't calculate EP offset\n");
370
+		free(sections);
371
+		return matcher ? -1 : CL_EFORMAT;
372
+	    }
373
+	    if(!matcher)
374
+		cli_dbgmsg("Entry Point file offset: %u\n", ep);
375
+	}
376
+    }
377
+
378
+    if(matcher) {
379
+	fileinfo->ep = ep;
380
+	fileinfo->nsections = sect;
381
+	fileinfo->section = sections;
382
+	return 0;
383
+    } else {
384
+	free(sections);
385
+	return CL_SUCCESS;
386
+    }
307 387
 }
308 388
 
309
-int cli_machoheader(int fd, struct cli_exe_info *elfinfo)
389
+int cli_machoheader(int fd, struct cli_exe_info *fileinfo)
310 390
 {
311
-	struct macho_hdr hdr;
312
-	struct macho_load_cmd load_cmd;
313
-	struct macho_segment_cmd segment_cmd;
314
-	struct macho_segment_cmd64 segment_cmd64;
315
-	struct macho_section section;
316
-	struct macho_section64 section64;
317
-	unsigned int i, j, sect = 0, conv, m64, nsects, vaddr, vsize, offset;
391
+    return cli_scanmacho(fd, NULL, fileinfo);
392
+}
318 393
 
319
-    cli_dbgmsg("in cli_machoheader()\n");
394
+int cli_scanmacho_unibin(int fd, cli_ctx *ctx)
395
+{
396
+	struct macho_fat_header fat_header;
397
+	struct macho_fat_arch fat_arch;
398
+	unsigned int conv, i, matcher = 0;
399
+	int ret = CL_CLEAN;
400
+	struct stat sb;
401
+	off_t pos;
320 402
 
321
-    if(read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
322
-	cli_dbgmsg("cli_scanmacho: Can't read header\n");
323
-	return -1;
403
+    if(fstat(fd, &sb) == -1) {
404
+	cli_dbgmsg("cli_scanmacho_unibin: fstat failed for fd %d\n", fd);
405
+	return CL_ESTAT;
324 406
     }
325 407
 
326
-    if(hdr.magic == 0xfeedface) {
327
-	conv = 0;
328
-	m64 = 0;
329
-    } else if(hdr.magic == 0xcefaedfe) {
330
-	conv = 1;
331
-	m64 = 0;
332
-    } else if(hdr.magic == 0xfeedfacf) {
408
+    if(read(fd, &fat_header, sizeof(fat_header)) != sizeof(fat_header)) {
409
+	cli_dbgmsg("cli_scanmacho_unibin: Can't read fat_header\n");
410
+	return CL_EFORMAT;
411
+    }
412
+
413
+    if(fat_header.magic == 0xcafebabe) {
333 414
 	conv = 0;
334
-	m64 = 1;
335
-    } else if(hdr.magic == 0xcffaedfe) {
415
+    } else if(fat_header.magic == 0xbebafeca) {
336 416
 	conv = 1;
337
-	m64 = 1;
338 417
     } else {
339
-	cli_dbgmsg("cli_scanmacho: Incorrect magic\n");
418
+	cli_dbgmsg("cli_scanmacho_unibin: Incorrect magic\n");
340 419
 	return CL_EFORMAT;
341 420
     }
342 421
 
343
-    if((m64 && EC32(load_cmd.cmdsize, conv) % 8) || (!m64 && EC32(load_cmd.cmdsize, conv) % 4)) {
344
-	cli_dbgmsg("cli_scanmacho: Invalid command size (%u)\n", EC32(load_cmd.cmdsize, conv));
345
-	return -1;
422
+    fat_header.nfats = EC32(fat_header.nfats, conv);
423
+    if(fat_header.nfats > 32) {
424
+	cli_dbgmsg("cli_scanmacho_unibin: Invalid number of architectures\n");
425
+	RETURN_BROKEN;
346 426
     }
347
-
348
-    if(m64)
349
-	lseek(fd, 4, SEEK_CUR);
350
-
351
-    for(i = 0; i < EC32(hdr.ncmds, conv); i++) {
352
-	if(read(fd, &load_cmd, sizeof(load_cmd)) != sizeof(load_cmd)) {
353
-	    cli_dbgmsg("cli_scanmacho: Can't read load command\n");
354
-	    return -1;
355
-	}
356
-
357
-	if((m64 && EC32(load_cmd.cmd, conv) == 0x19) || (!m64 && EC32(load_cmd.cmd, conv) == 0x01)) { /* LC_SEGMENT */
358
-	    if(m64) {
359
-		if(read(fd, &segment_cmd64, sizeof(segment_cmd64)) != sizeof(segment_cmd64)) {
360
-		    cli_dbgmsg("cli_scanmacho: Can't read segment command\n");
361
-		    return -1;
362
-		}
363
-		nsects = EC32(segment_cmd64.nsects, conv);
364
-	    } else {
365
-		if(read(fd, &segment_cmd, sizeof(segment_cmd)) != sizeof(segment_cmd)) {
366
-		    cli_dbgmsg("cli_scanmacho: Can't read segment command\n");
367
-		    return -1;
368
-		}
369
-		nsects = EC32(segment_cmd.nsects, conv);
370
-	    }
371
-	    for(j = 0; j < nsects; j++) {
372
-		if(m64) {
373
-		    if(read(fd, &section64, sizeof(section64)) != sizeof(section64)) {
374
-			cli_dbgmsg("cli_scanmacho: Can't read section\n");
375
-			return -1;
376
-		    }
377
-		    vaddr = EC64(section64.addr, conv);
378
-		    vsize = EC64(section64.size, conv);
379
-		    offset = EC32(section64.offset, conv);
380
-		} else {
381
-		    if(read(fd, &section, sizeof(section)) != sizeof(section)) {
382
-			cli_dbgmsg("cli_scanmacho: Can't read section\n");
383
-			return -1;
384
-		    }
385
-		    vaddr = EC32(section.addr, conv);
386
-		    vsize = EC32(section.size, conv);
387
-		    offset = EC32(section.offset, conv);
388
-		}
389
-		sect++;
390
-	    }
391
-	} else {
392
-	    if(EC32(load_cmd.cmdsize, conv) > sizeof(load_cmd))
393
-		lseek(fd, EC32(load_cmd.cmdsize, conv) - sizeof(load_cmd), SEEK_CUR);
427
+    cli_dbgmsg("UNIBIN: Number of architectures: %u\n", (unsigned int) fat_header.nfats);
428
+    for(i = 0; i < fat_header.nfats; i++) {
429
+	if(read(fd, &fat_arch, sizeof(fat_arch)) != sizeof(fat_arch)) {
430
+	    cli_dbgmsg("cli_scanmacho_unibin: Can't read fat_arch\n");
431
+	    RETURN_BROKEN;
394 432
 	}
433
+	pos = lseek(fd, 0, SEEK_CUR);
434
+	fat_arch.offset = EC32(fat_arch.offset, conv);
435
+	fat_arch.size = EC32(fat_arch.size, conv);
436
+	cli_dbgmsg("UNIBIN: Binary %u of %u\n", i + 1, fat_header.nfats);
437
+	cli_dbgmsg("UNIBIN: File offset: %u\n", fat_arch.offset);
438
+	cli_dbgmsg("UNIBIN: File size: %u\n", fat_arch.size);
439
+	ret = cli_dumpscan(fd, fat_arch.offset, fat_arch.size, ctx);
440
+	lseek(fd, pos, SEEK_SET);
441
+	if(ret == CL_VIRUS)
442
+	    break;
395 443
     }
396 444
 
397
-    return 0;
445
+    return ret; /* result from the last binary */
398 446
 }
... ...
@@ -24,7 +24,8 @@
24 24
 #include "others.h"
25 25
 #include "execs.h"
26 26
 
27
-int cli_scanmacho(int fd, cli_ctx *ctx);
28
-int cli_machoheader(int fd, struct cli_exe_info *elfinfo);
27
+int cli_scanmacho(int fd, cli_ctx *ctx, struct cli_exe_info *fileinfo);
28
+int cli_machoheader(int fd, struct cli_exe_info *fileinfo);
29
+int cli_scanmacho_unibin(int fd, cli_ctx *ctx);
29 30
 
30 31
 #endif
... ...
@@ -44,7 +44,7 @@
44 44
 #include "str.h"
45 45
 #include "cltypes.h"
46 46
 #include "default.h"
47
-
47
+#include "macho.h"
48 48
 
49 49
 int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset, cli_ctx *ctx, cli_file_t ftype, struct cli_ac_data **acdata)
50 50
 {
... ...
@@ -131,6 +131,8 @@ off_t cli_caloff(const char *offstr, struct cli_target_info *info, int fd, cli_f
131 131
 		einfo = cli_peheader;
132 132
 	    else if(ftype == CL_TYPE_ELF)
133 133
 		einfo = cli_elfheader;
134
+	    else if(ftype == CL_TYPE_MACHO)
135
+		einfo = cli_machoheader;
134 136
 
135 137
 	    if(einfo) {
136 138
 		if((pos = lseek(fd, 0, SEEK_CUR)) == -1) {
... ...
@@ -104,7 +104,7 @@ struct cli_mtarget {
104 104
     uint8_t ac_only;
105 105
 };
106 106
 
107
-#define CLI_MTARGETS 9
107
+#define CLI_MTARGETS 10
108 108
 static const struct cli_mtarget cli_mtargets[CLI_MTARGETS] =  {
109 109
     { 0,		    "GENERIC",	    0,	0   },
110 110
     { CL_TYPE_MSEXE,	    "PE",	    1,	0   },
... ...
@@ -114,7 +114,8 @@ static const struct cli_mtarget cli_mtargets[CLI_MTARGETS] =  {
114 114
     { CL_TYPE_GRAPHICS,	    "GRAPHICS",	    5,	1   },
115 115
     { CL_TYPE_ELF,	    "ELF",	    6,	1   },
116 116
     { CL_TYPE_TEXT_ASCII,   "ASCII",	    7,	1   },
117
-    { CL_TYPE_PE_DISASM,    "DISASM",	    8,	1   }
117
+    { CL_TYPE_PE_DISASM,    "DISASM",	    8,	1   },
118
+    { CL_TYPE_MACHO,	    "MACH-O",	    9,	1   }
118 119
 };
119 120
 
120 121
 struct cli_target_info {
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2007-2008 Sourcefire, Inc.
2
+ *  Copyright (C) 2007-2009 Sourcefire, Inc.
3 3
  *
4 4
  *  Authors: Tomasz Kojm, Trog
5 5
  *
... ...
@@ -71,6 +71,7 @@
71 71
 #include "ltdl.h"
72 72
 #include "matcher-ac.h"
73 73
 #include "default.h"
74
+#include "scanners.h"
74 75
 
75 76
 #ifndef	O_BINARY
76 77
 #define	O_BINARY	0
... ...
@@ -837,6 +838,65 @@ int cli_rmdirs(const char *dirname)
837 837
 }
838 838
 #endif
839 839
 
840
+int cli_dumpscan(int fd, off_t offset, size_t size, cli_ctx *ctx)
841
+{
842
+	int newfd, bread, sum = 0, ret;
843
+	char buff[FILEBUFF];
844
+	char *name;
845
+
846
+    if(offset) {
847
+	if(lseek(fd, offset, SEEK_SET) == -1) {
848
+	    cli_dbgmsg("cli_dumpscan: Can't lseek to %u\n", (unsigned int) offset);
849
+	    return CL_EFORMAT; /* most likely because of corrupted file */
850
+	}
851
+    }
852
+
853
+    if(!(name = cli_gentemp(ctx->engine->tmpdir)))
854
+	return CL_EMEM;
855
+
856
+    if((newfd = open(name, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
857
+	cli_errmsg("cli_dumpscan: Can't create file %s\n", name);
858
+	free(name);
859
+	return CL_ECREAT;
860
+    }
861
+
862
+    while((bread = cli_readn(fd, buff, FILEBUFF)) > 0) {
863
+	if((uint32_t) (sum + bread) >= size) {
864
+	    if(write(newfd, buff, size - sum) == -1) {
865
+		cli_errmsg("cli_dumpscan: Can't write to %s\n", name);
866
+		cli_unlink(name);
867
+		free(name);
868
+		close(newfd);
869
+		return CL_EWRITE;
870
+	    }
871
+	    break;
872
+	} else {
873
+	    if(write(newfd, buff, bread) == -1) {
874
+		cli_errmsg("cli_dumpscan: Can't write to %s\n", name);
875
+		cli_unlink(name);
876
+		free(name);
877
+		close(newfd);
878
+		return CL_EWRITE;
879
+	    }
880
+	}
881
+	sum += bread;
882
+    }
883
+    cli_dbgmsg("DUMP&SCAN: File extracted to %s\n", name);
884
+    lseek(newfd, 0, SEEK_SET);
885
+    if((ret = cli_magic_scandesc(newfd, ctx)) == CL_VIRUS)
886
+	cli_dbgmsg("cli_dumpscan: Infected with %s\n", *ctx->virname);
887
+
888
+    close(newfd);
889
+    if(!ctx->engine->keeptmp) {
890
+	if(cli_unlink(name)) {
891
+	    free(name);
892
+	    return CL_EUNLINK;
893
+	}
894
+    }
895
+    free(name);
896
+    return ret;
897
+}
898
+
840 899
 /* Implement a generic bitset, trog@clamav.net */
841 900
 
842 901
 #define BITS_PER_CHAR (8)
... ...
@@ -45,7 +45,7 @@
45 45
  * in re-enabling affected modules.
46 46
  */
47 47
 
48
-#define CL_FLEVEL 45
48
+#define CL_FLEVEL 46
49 49
 #define CL_FLEVEL_DCONF	CL_FLEVEL
50 50
 
51 51
 extern uint8_t cli_debug_flag;
... ...
@@ -351,6 +351,12 @@ void cli_errmsg(const char *str, ...);
351 351
 #define UNLIKELY(cond) (cond)
352 352
 #endif
353 353
 
354
+#ifdef __GNUC__
355
+#define always_inline inline __attribute__((always_inline))
356
+#else
357
+#define always_inline inline
358
+#endif
359
+
354 360
 #define cli_dbgmsg (!UNLIKELY(cli_debug_flag)) ? (void)0 : cli_dbgmsg_internal
355 361
 
356 362
 #ifdef __GNUC__
... ...
@@ -375,6 +381,7 @@ char *cli_gentemp(const char *dir);
375 375
 int cli_gentempfd(const char *dir, char **name, int *fd);
376 376
 unsigned int cli_rndnum(unsigned int max);
377 377
 int cli_filecopy(const char *src, const char *dest);
378
+int cli_dumpscan(int fd, off_t offset, size_t size, cli_ctx *ctx);
378 379
 bitset_t *cli_bitset_init(void);
379 380
 void cli_bitset_free(bitset_t *bs);
380 381
 int cli_bitset_set(bitset_t *bs, unsigned long bit_offset);
... ...
@@ -532,7 +532,7 @@ static int cli_checkoffset(const char *offset, unsigned int type)
532 532
     if(!strncmp(offset, "EOF-", 4))
533 533
 	return 0;
534 534
 
535
-    if((type == 1 || type == 6) && (!strncmp(offset, "EP+", 3) || !strncmp(offset, "EP-", 3) || (sscanf(offset, "SL+%u", &foo) == 1) || (sscanf(offset, "S%u+%u", &foo, &foo) == 2)))
535
+    if((type == 1 || type == 6 || type == 9) && (!strncmp(offset, "EP+", 3) || !strncmp(offset, "EP-", 3) || (sscanf(offset, "SL+%u", &foo) == 1) || (sscanf(offset, "S%u+%u", &foo, &foo) == 2)))
536 536
 	return 0;
537 537
 
538 538
     return 1;
... ...
@@ -2095,7 +2095,12 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
2095 2095
 
2096 2096
 	case CL_TYPE_MACHO:
2097 2097
 	    if(ctx->dconf->macho)
2098
-		ret = cli_scanmacho(desc, ctx);
2098
+		ret = cli_scanmacho(desc, ctx, NULL);
2099
+	    break;
2100
+
2101
+	case CL_TYPE_MACHO_UNIBIN:
2102
+	    if(ctx->dconf->macho)
2103
+		ret = cli_scanmacho_unibin(desc, ctx);
2099 2104
 	    break;
2100 2105
 
2101 2106
 	case CL_TYPE_SIS:
... ...
@@ -22,7 +22,7 @@ if HAVE_LIBCHECK
22 22
 check_clamav_SOURCES = check_clamav.c checks.h checks_common.h $(top_builddir)/libclamav/clamav.h\
23 23
 		       check_jsnorm.c check_str.c check_regex.c\
24 24
 		       check_disasm.c check_uniq.c check_matchers.c\
25
-		       check_htmlnorm.c
25
+		       check_htmlnorm.c check_bytecode.c
26 26
 check_clamav_CPPFLAGS = -I$(top_srcdir) @CHECK_CPPFLAGS@ -DSRCDIR=\"$(abs_srcdir)\"
27 27
 check_clamav_LDADD = $(top_builddir)/libclamav/libclamav.la @THREAD_LIBS@ @CHECK_LIBS@
28 28
 check_clamd_SOURCES = check_clamd.c checks_common.h
... ...
@@ -56,7 +56,8 @@ am__EXEEXT_1 = check_clamav$(EXEEXT)
56 56
 am__check_clamav_SOURCES_DIST = check_clamav_skip.c check_clamav.c \
57 57
 	checks.h checks_common.h $(top_builddir)/libclamav/clamav.h \
58 58
 	check_jsnorm.c check_str.c check_regex.c check_disasm.c \
59
-	check_uniq.c check_matchers.c check_htmlnorm.c
59
+	check_uniq.c check_matchers.c check_htmlnorm.c \
60
+	check_bytecode.c
60 61
 @HAVE_LIBCHECK_FALSE@am_check_clamav_OBJECTS =  \
61 62
 @HAVE_LIBCHECK_FALSE@	check_clamav-check_clamav_skip.$(OBJEXT)
62 63
 @HAVE_LIBCHECK_TRUE@am_check_clamav_OBJECTS =  \
... ...
@@ -67,7 +68,8 @@ am__check_clamav_SOURCES_DIST = check_clamav_skip.c check_clamav.c \
67 67
 @HAVE_LIBCHECK_TRUE@	check_clamav-check_disasm.$(OBJEXT) \
68 68
 @HAVE_LIBCHECK_TRUE@	check_clamav-check_uniq.$(OBJEXT) \
69 69
 @HAVE_LIBCHECK_TRUE@	check_clamav-check_matchers.$(OBJEXT) \
70
-@HAVE_LIBCHECK_TRUE@	check_clamav-check_htmlnorm.$(OBJEXT)
70
+@HAVE_LIBCHECK_TRUE@	check_clamav-check_htmlnorm.$(OBJEXT) \
71
+@HAVE_LIBCHECK_TRUE@	check_clamav-check_bytecode.$(OBJEXT)
71 72
 check_clamav_OBJECTS = $(am_check_clamav_OBJECTS)
72 73
 @HAVE_LIBCHECK_TRUE@check_clamav_DEPENDENCIES =  \
73 74
 @HAVE_LIBCHECK_TRUE@	$(top_builddir)/libclamav/libclamav.la
... ...
@@ -265,7 +267,7 @@ check_SCRIPTS = $(scripts)
265 265
 @HAVE_LIBCHECK_TRUE@check_clamav_SOURCES = check_clamav.c checks.h checks_common.h $(top_builddir)/libclamav/clamav.h\
266 266
 @HAVE_LIBCHECK_TRUE@		       check_jsnorm.c check_str.c check_regex.c\
267 267
 @HAVE_LIBCHECK_TRUE@		       check_disasm.c check_uniq.c check_matchers.c\
268
-@HAVE_LIBCHECK_TRUE@		       check_htmlnorm.c
268
+@HAVE_LIBCHECK_TRUE@		       check_htmlnorm.c check_bytecode.c
269 269
 
270 270
 @HAVE_LIBCHECK_TRUE@check_clamav_CPPFLAGS = -I$(top_srcdir) @CHECK_CPPFLAGS@ -DSRCDIR=\"$(abs_srcdir)\"
271 271
 @HAVE_LIBCHECK_TRUE@check_clamav_LDADD = $(top_builddir)/libclamav/libclamav.la @THREAD_LIBS@ @CHECK_LIBS@
... ...
@@ -334,6 +336,7 @@ mostlyclean-compile:
334 334
 distclean-compile:
335 335
 	-rm -f *.tab.c
336 336
 
337
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_clamav-check_bytecode.Po@am__quote@
337 338
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_clamav-check_clamav.Po@am__quote@
338 339
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_clamav-check_clamav_skip.Po@am__quote@
339 340
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_clamav-check_disasm.Po@am__quote@
... ...
@@ -493,6 +496,20 @@ check_clamav-check_htmlnorm.obj: check_htmlnorm.c
493 493
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
494 494
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_clamav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o check_clamav-check_htmlnorm.obj `if test -f 'check_htmlnorm.c'; then $(CYGPATH_W) 'check_htmlnorm.c'; else $(CYGPATH_W) '$(srcdir)/check_htmlnorm.c'; fi`
495 495
 
496
+check_clamav-check_bytecode.o: check_bytecode.c
497
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_clamav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT check_clamav-check_bytecode.o -MD -MP -MF $(DEPDIR)/check_clamav-check_bytecode.Tpo -c -o check_clamav-check_bytecode.o `test -f 'check_bytecode.c' || echo '$(srcdir)/'`check_bytecode.c
498
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/check_clamav-check_bytecode.Tpo $(DEPDIR)/check_clamav-check_bytecode.Po
499
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='check_bytecode.c' object='check_clamav-check_bytecode.o' libtool=no @AMDEPBACKSLASH@
500
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
501
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_clamav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o check_clamav-check_bytecode.o `test -f 'check_bytecode.c' || echo '$(srcdir)/'`check_bytecode.c
502
+
503
+check_clamav-check_bytecode.obj: check_bytecode.c
504
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_clamav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT check_clamav-check_bytecode.obj -MD -MP -MF $(DEPDIR)/check_clamav-check_bytecode.Tpo -c -o check_clamav-check_bytecode.obj `if test -f 'check_bytecode.c'; then $(CYGPATH_W) 'check_bytecode.c'; else $(CYGPATH_W) '$(srcdir)/check_bytecode.c'; fi`
505
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/check_clamav-check_bytecode.Tpo $(DEPDIR)/check_clamav-check_bytecode.Po
506
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='check_bytecode.c' object='check_clamav-check_bytecode.obj' libtool=no @AMDEPBACKSLASH@
507
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
508
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_clamav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o check_clamav-check_bytecode.obj `if test -f 'check_bytecode.c'; then $(CYGPATH_W) 'check_bytecode.c'; else $(CYGPATH_W) '$(srcdir)/check_bytecode.c'; fi`
509
+
496 510
 check_clamd-check_clamav_skip.o: check_clamav_skip.c
497 511
 @am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_clamd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT check_clamd-check_clamav_skip.o -MD -MP -MF $(DEPDIR)/check_clamd-check_clamav_skip.Tpo -c -o check_clamd-check_clamav_skip.o `test -f 'check_clamav_skip.c' || echo '$(srcdir)/'`check_clamav_skip.c
498 512
 @am__fastdepCC_TRUE@	mv -f $(DEPDIR)/check_clamd-check_clamav_skip.Tpo $(DEPDIR)/check_clamd-check_clamav_skip.Po
499 513
new file mode 100644
... ...
@@ -0,0 +1,90 @@
0
+/*
1
+ *  Unit tests for bytecode functions. 
2
+ *
3
+ *  Copyright (C) 2009 Sourcefire, Inc.
4
+ *
5
+ *  Authors: Török Edvin
6
+ *
7
+ *  This program is free software; you can redistribute it and/or modify
8
+ *  it under the terms of the GNU General Public License version 2 as
9
+ *  published by the Free Software Foundation.
10
+ *
11
+ *  This program is distributed in the hope that it will be useful,
12
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ *  GNU General Public License for more details.
15
+ *
16
+ *  You should have received a copy of the GNU General Public License
17
+ *  along with this program; if not, write to the Free Software
18
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
+ *  MA 02110-1301, USA.
20
+ */
21
+#if HAVE_CONFIG_H
22
+#include "clamav-config.h"
23
+#endif
24
+
25
+#include <stdio.h>
26
+
27
+#include <stdlib.h>
28
+#include <limits.h>
29
+#include <string.h>
30
+#include <check.h>
31
+#include "../libclamav/clamav.h"
32
+#include "../libclamav/others.h"
33
+#include "../libclamav/bytecode.h"
34
+#include "checks.h"
35
+
36
+static void runtest(const char *file, uint64_t expected)
37
+{
38
+    int rc;
39
+    int fd = open_testfile(file);
40
+    FILE *f;
41
+    struct cli_bc bc;
42
+    struct cli_bc_ctx *ctx;
43
+    uint64_t v;
44
+
45
+    fail_unless(fd >= 0, "retmagic open failed");
46
+    f = fdopen(fd, "r");
47
+    fail_unless(!!f, "retmagic fdopen failed");
48
+
49
+    cl_debug();
50
+
51
+    rc = cli_bytecode_load(&bc, f, NULL);
52
+    fail_unless(rc == CL_SUCCESS, "cli_bytecode_load failed");
53
+    fclose(f);
54
+
55
+    ctx = cli_bytecode_context_alloc();
56
+    fail_unless(!!ctx, "cli_bytecode_context_alloc failed");
57
+
58
+    cli_bytecode_context_setfuncid(ctx, &bc, 0);
59
+    rc = cli_bytecode_run(&bc, ctx);
60
+    fail_unless(rc == CL_SUCCESS, "cli_bytecode_run failed");
61
+
62
+    v = cli_bytecode_context_getresult_int(ctx);
63
+    fail_unless_fmt(v == expected, "Invalid return value from bytecode run, expected: %llx, have: %llx\n",
64
+		    expected, v);
65
+    cli_bytecode_context_destroy(ctx);
66
+    cli_bytecode_destroy(&bc);
67
+}
68
+
69
+START_TEST (test_retmagic)
70
+{
71
+    runtest("input/retmagic.cbc", 0x1234f00d);
72
+}
73
+END_TEST
74
+
75
+START_TEST (test_arith)
76
+{
77
+    runtest("input/arith.cbc", 0xd5555555);
78
+}
79
+END_TEST
80
+Suite *test_bytecode_suite(void)
81
+{
82
+    Suite *s = suite_create("bytecode");
83
+    TCase *tc_cli_arith = tcase_create("arithmetic");
84
+    suite_add_tcase(s, tc_cli_arith);
85
+
86
+    tcase_add_test(tc_cli_arith, test_retmagic);
87
+    tcase_add_test(tc_cli_arith, test_arith);
88
+    return s;
89
+}
... ...
@@ -534,6 +534,7 @@ int main(void)
534 534
     srunner_add_suite(sr, test_uniq_suite());
535 535
     srunner_add_suite(sr, test_matchers_suite());
536 536
     srunner_add_suite(sr, test_htmlnorm_suite());
537
+    srunner_add_suite(sr, test_bytecode_suite());
537 538
 
538 539
     srunner_set_log(sr, "test.log");
539 540
     if(freopen("test-stderr.log","w+",stderr) == NULL) {
... ...
@@ -9,6 +9,7 @@ Suite *test_disasm_suite(void);
9 9
 Suite *test_uniq_suite(void);
10 10
 Suite *test_matchers_suite(void);
11 11
 Suite *test_htmlnorm_suite(void);
12
+Suite *test_bytecode_suite(void);
12 13
 void errmsg_expected(void);
13 14
 int open_testfile(const char *name);
14 15
 void diff_files(int fd, int reffd);
15 16
new file mode 100644
... ...
@@ -0,0 +1,351 @@
0
+ClamBCaa`|`````|`bbep`clamcoincidencejb
1
+A`Lbabb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bb`bFbbbaa
2
+Bb`b`oa`abb`baaoa`acb`baboa`adb`bacoa`aeb`badoa`afb`baeoa`agb`bafoa`ahb`bagoa`aib`bahoa`ajb`baioa`akb`bajoa`alb`bakoa`amb`baloa`anb`bamoa`aob`banoa`b`ab`baooa`baab`bb`aoa`bbab`bbaaa`aa`b`bbbaa`baaabb`bbcaa`bbaacb`bbdaa`bcaadb`bbeaa`bdaaeb`bbfaa`beaafb`bbgaa`bfaagb`bbhaa`bgaahb`bbiaa`bhaaib`bbjaa`biaajb`bbkaa`bjaakb`bblaa`bkaalb`bbmaa`blaamb`bbnaa`bmaanb`bboaa`bnaaob`bb`ba`boab`aTcab`bE
3
+A`Lb`cahaab`bahaab`bahaab`bahaab`bb`aaab`bb`aaab`bb`aaab`bb`aaab`bb`baab`bb`baab`bb`baab`bb`baab`bb`daab`bb`daab`bb`daab`bb`daab`bFbaebab
4
+Bah`oabbcaAaAaaaaada`AbTaaaaabaa
5
+Bb`baboaabga@Tcaab
6
+BahacoabbcaAaBooaaaddaac@Taaadadac
7
+Bb`baeoaabga@Tcaae
8
+BahafoabbcaBooBooaaagdaafBnoTaaagafae
9
+Bb`bahoaabga@Tcaah
10
+BahaioabbcaBooAaaaajdaai@Taaajahag
11
+Bb`bakoaabga@Tcaak
12
+Bb`aaloabbdaAaAaaaamdaalAbTaaamajai
13
+Bb`banoaabga@Tcaan
14
+Bb`aaooabbdaAaDooooaab`adaao@Taab`aalak
15
+Bb`bbaaoaabga@Tcabaa
16
+Bb`abbaoabbdaDooooDooooaabcadabbaDnoooTaabcaanam
17
+Bb`bbdaoaabga@Tcabda
18
+Bb`abeaoabbdaDooooAaaabfadabea@Taabfab`aao
19
+Bb`bbgaoaabga@Tcabga
20
+Bb`bbhaoabbeaAaAaaabiadabhaAbTaabiabbabaa
21
+Bb`bbjaoaabga@Tcabja
22
+Bb`bbkaoabbeaAaHooooooooaabladabka@Taablabdabca
23
+Bb`bbmaoaabga@Tcabma
24
+Bb`bbnaoabbeaHooooooooHooooooooaaboadabnaHnoooooooTaaboabfabea
25
+Bb`bb`boaabga@Tcab`b
26
+Bb`bbaboabbeaHooooooooAaaabbbdabab@Taabbbbhabga
27
+Bb`bbcboaabga@Tcabcb
28
+Bb`dbdboabbfaAaAaaabebdabdbAbTaabebbjabia
29
+Bb`bbfboaabga@Tcabfb
30
+Bb`dbgboabbfaAaPooooooooooooooooaabhbdabgb@Taabhbblabka
31
+Bb`bbiboaabga@Tcabib
32
+Bb`dbjboabbfaPooooooooooooooooPooooooooooooooooaabkbdabjbPnoooooooooooooooTaabkbbnabma
33
+Bb`bblboaabga@Tcablb
34
+Bb`dbmboabbfaPooooooooooooooooAaaabnbdabmb@Taabnbb`bboa
35
+Bb`bboboaabga@Tcabob
36
+BTcaAaE
37
+A`Lbdbahaab`bahaab`bahaab`bb`aaab`bb`aaab`bb`aaab`bb`baab`bb`baab`bb`baab`bb`daab`bb`daab`bb`daab`bFbmcbia
38
+Bah`oabbhaBooAaaaaada`BnoTaaaaabaa
39
+Bb`baboaabga@Tcaab
40
+BahacoabbhaAaBooaaaddaacAbTaaadadac
41
+Bb`baeoaabga@Tcaae
42
+BahafoabbhaAaAaaaagdaaf@Taaagafae
43
+Bb`bahoaabga@Tcaah
44
+Bb`aaioabbiaDooooAaaaajdaaiDnoooTaaajahag
45
+Bb`bakoaabga@Tcaak
46
+Bb`aaloabbiaAaDooooaaamdaalAbTaaamajai
47
+Bb`banoaabga@Tcaan
48
+Bb`aaooabbiaAaAaaab`adaao@Taab`aalak
49
+Bb`bbaaoaabga@Tcabaa
50
+Bb`bbbaoabbjaHooooooooAaaabcadabbaHnoooooooTaabcaanam
51
+Bb`bbdaoaabga@Tcabda
52
+Bb`bbeaoabbjaAaHooooooooaabfadabeaAbTaabfab`aao
53
+Bb`bbgaoaabga@Tcabga
54
+Bb`bbhaoabbjaAaAaaabiadabha@Taabiabbabaa
55
+Bb`bbjaoaabga@Tcabja
56
+Bb`dbkaoabbkaPooooooooooooooooAaaabladabkaPnoooooooooooooooTaablabdabca
57
+Bb`bbmaoaabga@Tcabma
58
+Bb`dbnaoabbkaAaPooooooooooooooooaaboadabnaAbTaaboabfabea
59
+Bb`bb`boaabga@Tcab`b
60
+Bb`dbaboabbkaAaAaaabbbdabab@Taabbbbhabga
61
+Bb`bbcboaabga@Tcabcb
62
+BTcaAdE
63
+A`Lb`cahaab`bahaab`bahaab`bahaab`bb`aaab`bb`aaab`bb`aaab`bb`aaab`bb`baab`bb`baab`bb`baab`bb`baab`bb`daab`bb`daab`bb`daab`bb`daab`bFbaebab
64
+Bah`oabblaBooAaaaaada`BooTaaaaabaa
65
+Bb`baboaabga@Tcaab
66
+BahacoabblaBooBooaaaddaacAaTaaadadac
67
+Bb`baeoaabga@Tcaae
68
+BahafoabblaAaAaaaagdaafAaTaaagafae
69
+Bb`bahoaabga@Tcaah
70
+BahaioabblaBaaBcbaaajdaaiBceTaaajahag
71
+Bb`bakoaabga@Tcaak
72
+Bb`aaloabbmaDooooAaaaamdaalDooooTaaamajai
73
+Bb`banoaabga@Tcaan
74
+Bb`aaooabbmaDooooDooooaab`adaaoAaTaab`aalak
75
+Bb`bbaaoaabga@Tcabaa
76
+Bb`abbaoabbmaAaAaaabcadabbaAaTaabcaanam
77
+Bb`bbdaoaabga@Tcabda
78
+Bb`abeaoabbmaBckCgfcaabfadabeaDe`afTaabfab`aao
79
+Bb`bbgaoaabga@Tcabga
80
+Bb`bbhaoabbnaHooooooooAaaabiadabhaHooooooooTaabiabbabaa
81
+Bb`bbjaoaabga@Tcabja
82
+Bb`bbkaoabbnaHooooooooHooooooooaabladabkaAaTaablabdabca
83
+Bb`bbmaoaabga@Tcabma
84
+Bb`bbnaoabbnaAaAaaaboadabnaAaTaaboabfabea
85
+Bb`bb`boaabga@Tcab`b
86
+Bb`bbaboabbnaE`emkbEhnmdmaabbbdababH`h`jlgbgTaabbbbhabga
87
+Bb`bbcboaabga@Tcabcb
88
+Bb`dbdboabboaPooooooooooooooooAaaabebdabdbPooooooooooooooooTaabebbjabia
89
+Bb`bbfboaabga@Tcabfb
90
+Bb`dbgboabboaPooooooooooooooooPooooooooooooooooaabhbdabgbAaTaabhbblabka
91
+Bb`bbiboaabga@Tcabib
92
+Bb`dbjboabboaAaAaaabkbdabjbAaTaabkbbnabma
93
+Bb`bblboaabga@Tcablb
94
+Bb`dbmboabboaImaghnanbdIogjdckg`baabnbdabmbPcfifjghokjjemflgTaabnbb`bboa
95
+Bb`bboboaabga@Tcabob
96
+BTcaB`aE
97
+A`Lacb`aaab`bFafac
98
+Bb`a`oabbabDjnmoAgaaaada`DfddbTaaaaabaa
99
+Bb`baboaabga@Tcaab
100
+BTcaB`dE
101
+A`Lbfaahaab`bahaab`bahaab`bahaab`bahahaab`bahaab`bb`aaab`bFbebao
102
+Bah`oabbdbAaBooaaaada`BooTaaaaabaa
103
+Bb`baboaabga@Tcaab
104
+BahacoabbdbBooAaaaaddaacBooTaaadadac
105
+Bb`baeoaabga@Tcaae
106
+BahafoabbdbBooBooaaagdaafAaTaaagafae
107
+Bb`bahoaabga@Tcaah
108
+BahaioabbdbAaAaaaajdaaiAaTaaajahag
109
+Bb`bakoaabga@Tcaak
110
+BahaloabbcaBnoAeahamoabbdbAfalaaandaamAbTaaanajai
111
+Bb`baooaabga@Tcaao
112
+Bahb`aoabbdbalAbaabaadab`aAaTaabaaalak
113
+Bb`bbbaoaabga@Tcabba
114
+Bb`abcaoabbebDjnmoAgaabdadabcaDdkooTaabdaanam
115
+Bb`bbeaoaabga@Tcabea
116
+BTcaC``aE
117
+A`Laoahaab`bahaab`bahaab`bb`aaab`bb`aaab`bFbjaak
118
+Bah`oabblbBooAaaaaada`@Taaaaabaa
119
+Bb`baboaabga@Tcaab
120
+BahacoabbhbBooAaaaaddaac@Taaadadac
121
+Bb`baeoaabga@Tcaae
122
+BahafoabblbAaBooaaagdaaf@Taaagafae
123
+Bb`bahoaabga@Tcaah
124
+Bb`aaioabbmbDinmoAgaaajdaaiDmoooTaaajahag
125
+Bb`bakoaabga@Tcaak
126
+Bb`aaloabbibDinmoAgaaamdaalAfTaaamajai
127
+Bb`banoaabga@Tcaan
128
+BTcaC``dE
129
+A`Lalahaab`bahaab`bahaab`bb`aaab`bFbeaai
130
+Bah`oabb`cAaAaaaaada`AbTaaaaabaa
131
+Bb`baboaabga@Tcaab
132
+Bahacoabb`cAa@aaaddaacAaTaaadadac
133
+Bb`baeoaabga@Tcaae
134
+Bahafoabb`cBnoAbaaagdaafBhoTaaagafae
135
+Bb`bahoaabga@Tcaah
136
+Bb`aaioabbacDnojoAbaaajdaaiDhoknTaaajahag
137
+Bb`bakoaabga@Tcaak
138
+BTcaD```aE
139
+A`Lagahaab`bahahaab`bFalae
140
+Bah`oabbdcBnoAaaaaada`BogTaaaaabaa
141
+Bb`baboaabga@Tcaab
142
+BahacoabbcaBnoAeahadoabbdcacAaaaaedaadAaTaaaeadac
143
+Bb`bafoaabga@Tcaaf
144
+BTcaD```dE
145
+A`Lafahaab`bahaab`bFakae
146
+Bah`oabbhcBnoAaaaaada`BooTaaaaabaa
147
+Bb`baboaabga@Tcaab
148
+BahacoabbhcBngAaaaaddaacBocTaaadadac
149
+Bb`baeoaabga@Tcaae
150
+BTcaE````aE
151
+A`Lalahaab`bb`aaab`bb`baab`bb`daab`bFbeaai
152
+Bah`oabblcBjeAoaaaada`AjTaaaaabaa
153
+Bb`baboaabga@Tcaab
154
+Bb`aacoabbmcDlkjeD```oaaaddaacD```eTaaadadac
155
+Bb`baeoaabga@Tcaae
156
+Bb`bafoabbncHdcbalkjeG``````oaaagdaafG``````jTaaagafae
157
+Bb`bahoaabga@Tcaah
158
+Bb`daioabbocPdcbahgfedcbalkjeG``````oaaajdaaiG``````fTaaajahag
159
+Bb`bakoaabga@Tcaak
160
+BTcaE````dE
161
+A`Lalahaab`bb`aaab`bb`baab`bb`daab`bFbeaai
162
+Bah`oabb`dBjeAoaaaada`BoeTaaaaabaa
163
+Bb`baboaabga@Tcaab
164
+Bb`aacoabbadDlkjeD```oaaaddaacDlkjoTaaadadac
165
+Bb`baeoaabga@Tcaae
166
+Bb`bafoabbbdHdcbalkjeG``````oaaagdaafHdcbalkoeTaaagafae
167
+Bb`bahoaabga@Tcaah
168
+Bb`daioabbcdPdcbahgfedcbalkjeG``````oaaajdaaiPdcbahgoedcbalkjeTaaajahag
169
+Bb`bakoaabga@Tcaak
170
+BTcaF`````aE
171
+A`Lalahaab`bb`aaab`bb`baab`bb`daab`bFbeaai
172
+Bah`oabbddBjeB`oaaaada`BjjTaaaaabaa
173
+Bb`baboaabga@Tcaab
174
+Bb`aacoabbedDjejeD``ooaaaddaacDjeejTaaadadac
175
+Bb`baeoaabga@Tcaae
176
+Bb`bafoabbfdHjejejejeH``ooooooaaagdaafHjeejejejTaaagafae
177
+Bb`bahoaabga@Tcaah
178
+Bb`daioabbgdPjejejejejejejejeP``ooooooooooooooaaajdaaiPjeejejejejejejejTaaajahag
179
+Bb`bakoaabga@Tcaak
180
+BTcaF`````dE
181
+A`Laib`aaab`bb`baab`bb`daab`bFb`aag
182
+Bb`a`oaabhdBloaaaada`DloooTaaaaabaa
183
+Bb`baboaabga@Tcaab
184
+Bb`bacoaabidDjoooaaaddaacHjoooooooTaaadadac
185
+Bb`baeoaabga@Tcaae
186
+Bb`dafoaabjdHjoooooooaaagdaafPjoooooooooooooooTaaagafae
187
+Bb`bahoaabga@Tcaah
188
+BTcaG``````aE
189
+A`Laib`aaab`bb`baab`bb`daab`bFb`aag
190
+Bb`a`oaabkdBloaaaada`BloTaaaaabaa
191
+Bb`baboaabga@Tcaab
192
+Bb`bacoaabldDloooaaaddaacDloooTaaadadac
193
+Bb`baeoaabga@Tcaae
194
+Bb`dafoaabmdHloooooooaaagdaafHloooooooTaaagafae
195
+Bb`bahoaabga@Tcaah
196
+BTcaG``````dE
197
+A`Laiahaab`bb`aaab`bb`baab`bFb`aag
198
+Bah`oaabndDmnnoaaaada`BmnTaaaaabaa
199
+Bb`baboaabga@Tcaab
200
+Bb`aacoaabodHmnnomjnmaaaddaacDmnnoTaaadadac
201
+Bb`baeoaabga@Tcaae
202
+Bb`bafoaab`ePonnkmnnomjnmonnkaaagdaafHonnkmnnoTaaagafae
203
+Bb`bahoaabga@Tcaah
204
+BTcaH```````aE
205
+A`Laob`baab`bb`baab`bb`baab`bb`baab`bb`baab`bFbjaak
206
+Bb`b`oadbaeHooooooooAb@Adaaaada`CijbTaaaaabaa
207
+Bb`baboaabga@Tcaab
208
+Bb`bacoadbaeHooooooooHooooooooAaHooooooooaaaddaacCbbcTaaadadac
209
+Bb`baeoaabga@Tcaae
210
+Bb`bafoadbaeHoooooooo@AcHnoooooooaaagdaafCcjbTaaagafae
211
+Bb`bahoaabga@Tcaah
212
+Bb`baioadbaeHoooooooo@Ac@aaajdaaiCcnbTaaajahag
213
+Bb`bakoaabga@Tcaak
214
+Bb`baloadbaeHoooooooo@@HooooooooaaamdaalBkbTaaamajai
215
+Bb`banoaabga@Tcaan
216
+BTcaH```````dE
217
+A`Lafb`baab`bb`baab`bFakae
218
+Bb`b`oacbbeAdAeAfaaaada`AeTaaaaabaa
219
+Bb`baboaabga@Tcaab
220
+Bb`bacoacbbe@AeAfaaaddaacAfTaaadadac
221
+Bb`baeoaabga@Tcaae
222
+BTcaH```````hE
223
+AbLaaahahahFabaa
224
+Bahaba`aa`TcaabE
225
+AbLaab`ab`ab`aFabaa
226
+Bb`aaba`aa`TcaabE
227
+AbLaab`bb`bb`bFabaa
228
+Bb`baba`aa`TcaabE
229
+AbLaab`db`db`dFabaa
230
+Bb`daba`aa`TcaabE
231
+AaLaab`bb`bFabaa
232
+Bb`baae`Aa`TcaaaE
233
+AbLaaahahahFabaa
234
+Bahabb``aaTcaabE
235
+AbLaab`ab`ab`aFabaa
236
+Bb`aabb``aaTcaabE
237
+AbLaab`bb`bb`bFabaa
238
+Bb`babb``aaTcaabE
239
+AbLaab`db`db`dFabaa
240
+Bb`dabb``aaTcaabE
241
+AbLaaahahahFabaa
242
+Bahabc`aa`TcaabE
243
+AbLaab`ab`ab`aFabaa
244
+Bb`aabc`aa`TcaabE
245
+AbLaab`bb`bb`bFabaa
246
+Bb`babc`aa`TcaabE
247
+AbLaab`db`db`dFabaa
248
+Bb`dabc`aa`TcaabE
249
+AbLadahahb`bb`bb`bahFaeaa
250
+Bb`bab`a`b`bac`aaab`badd`abacahaen`adTcaaeE
251
+AbLadb`ab`ab`bb`bb`bb`aFaeaa
252
+Bb`bab`a`b`bac`aaab`badd`abacb`aaen`adTcaaeE
253
+AbLaab`bb`bb`bFabaa
254
+Bb`babd``aaTcaabE
255
+AbLaab`db`db`dFabaa
256
+Bb`dabd``aaTcaabE
257
+AbLadahahb`bb`bb`bahFaeaa
258
+Bb`babo``b`baco`aab`bade`abacahaen`adTcaaeE
259
+AbLadb`ab`ab`bb`bb`bb`aFaeaa
260
+Bb`babo``b`baco`aab`bade`abacb`aaen`adTcaaeE
261
+AbLaab`bb`bb`bFabaa
262
+Bb`babe``aaTcaabE
263
+AbLaab`db`db`dFabaa
264
+Bb`dabe``aaTcaabE
265
+AbLadahahb`bb`bb`bahFaeaa
266
+Bb`bab`a`b`bac`aaab`badf`abacahaen`adTcaaeE
267
+AbLadb`ab`ab`bb`bb`bb`aFaeaa
268
+Bb`bab`a`b`bac`aaab`badf`abacb`aaen`adTcaaeE
269
+AbLaab`bb`bb`bFabaa
270
+Bb`babf``aaTcaabE
271
+AbLaab`db`db`dFabaa
272
+Bb`dabf``aaTcaabE
273
+AbLadahahb`bb`bb`bahFaeaa
274
+Bb`babo``b`baco`aab`badg`abacahaen`adTcaaeE
275
+AbLadb`ab`ab`bb`bb`bb`aFaeaa
276
+Bb`babo``b`baco`aab`badg`abacb`aaen`adTcaaeE
277
+AbLaab`bb`bb`bFabaa
278
+Bb`babg``aaTcaabE
279
+AbLaab`db`db`dFabaa
280
+Bb`dabg``aaTcaabE
281
+AbLacahb`bb`bb`bahFadaa
282
+Bb`babo``b`bach`abaaahadn`acTcaadE
283
+AbLacb`ab`bb`bb`bb`aFadaa
284
+Bb`babo``b`bach`abaab`aadn`acTcaadE
285
+AbLaab`bb`bb`bFabaa
286
+Bb`babh``aaTcaabE
287
+AbLabb`db`bb`db`dFacaa
288
+Bb`dab`aaab`dach``abTcaacE
289
+AbLacahb`bb`bb`bahFadaa
290
+Bb`bab`a`b`baci`abaaahadn`acTcaadE
291
+AbLacb`ab`bb`bb`bb`aFadaa
292
+Bb`bab`a`b`baci`abaab`aadn`acTcaadE
293
+AbLaab`bb`bb`bFabaa
294
+Bb`babi``aaTcaabE
295
+AbLabb`db`bb`db`dFacaa
296
+Bb`dab`aaab`daci``abTcaacE
297
+AbLadahahb`bb`bb`bahFaeaa
298
+Bb`babo``b`baco`aab`badj`abacahaen`adTcaaeE
299
+AbLadb`ab`ab`bb`bb`bb`aFaeaa
300
+Bb`babo``b`baco`aab`badj`abacb`aaen`adTcaaeE
301
+AbLaab`bb`bb`bFabaa
302
+Bb`babj``aaTcaabE
303
+AbLaab`db`db`dFabaa
304
+Bb`dabj``aaTcaabE
305
+AbLaaahahahFabaa
306
+Bahabk`aa`TcaabE
307
+AbLaab`ab`ab`aFabaa
308
+Bb`aabk`aa`TcaabE
309
+AbLaab`bb`bb`bFabaa
310
+Bb`babk`aa`TcaabE
311
+AbLaab`db`db`dFabaa
312
+Bb`dabk`aa`TcaabE
313
+AbLaaahahahFabaa
314
+Bahabl`aa`TcaabE
315
+AbLaab`ab`ab`aFabaa
316
+Bb`aabl`aa`TcaabE
317
+AbLaab`bb`bb`bFabaa
318
+Bb`babl`aa`TcaabE
319
+AbLaab`db`db`dFabaa
320
+Bb`dabl`aa`TcaabE
321
+AbLaaahahahFabaa
322
+Bahabm`aa`TcaabE
323
+AbLaab`ab`ab`aFabaa
324
+Bb`aabm`aa`TcaabE
325
+AbLaab`bb`bb`bFabaa
326
+Bb`babm`aa`TcaabE
327
+AbLaab`db`db`dFabaa
328
+Bb`dabm`aa`TcaabE
329
+AaLaaahb`aFabaa
330
+Bb`aaao``TcaaaE
331
+AaLaab`ab`bFabaa
332
+Bb`baao``TcaaaE
333
+AaLaab`bb`dFabaa
334
+Bb`daao``TcaaaE
335
+AaLaaahb`aFabaa
336
+Bb`aaa`a`TcaaaE
337
+AaLaab`ab`bFabaa
338
+Bb`baa`a`TcaaaE
339
+AaLaab`bb`dFabaa
340
+Bb`daa`a`TcaaaE
341
+AaLaab`aahFabaa
342
+Bahaan``TcaaaE
343
+AaLaab`bb`aFabaa
344
+Bb`aaan``TcaaaE
345
+AaLaab`db`bFabaa
346
+Bb`baan``TcaaaE
347
+AdLbmab`bb`bb`bb`baab`baab`bb`baab`bb`baab`bb`baab`bb`baab`bb`baab`bb`baab`bb`baab`bb`baab`bb`bFbnaaa
348
+Baaadma`aab`bae`aadaaafjaaaabb`bagl`aeAbb`bahnaafaeagaaaija`aab`bajl`ahAdb`baknaaiajahaaalmaaaabb`baml`akAhb`bannaalakamaaaoha`acb`bb`al`anB`ab`bbaanaaob`aanaabbafaaaacb`bbcal`baaB`bb`bbdanabbabaabcaaabeahaabacb`bbfal`bdaB`db`bbganabeabdabfaaabhafa`acb`bbial`bgaB`hb`bbjanabhabiabgaaabkada`aab`bblal`bjaC``ab`bbmanabkablabjaaabnadaaaabb`bboal`bmaC``bb`bb`bnabnabmaboaTcab`bE
349
+AcLabb`bb`bb`baab`bFacaa
350
+Baaacea`@b`badnaacaaabTcaadE
0 351
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+ClamBCaa`|`````|`aap`clamcoincidencejb
1
+A`L`Faaaa
2
+BTcaHm``odcbaE